如何在 PHP 上将 hash_hmac() 与 "SHA256withRSA" 一起使用?

How to use hash_hmac() with "SHA256withRSA" on PHP?

我正在尝试让 PayPal Webhooks 与我的 PHP 应用程序一起使用。 问题是他们通过 headers 发送的散列算法,我必须使用它来验证请求是否有效。

当我尝试使用它时,出现此错误:

hash_hmac(): Unknown hashing algorithm: SHA256withRSA

我已经尝试 hash_hmac 仅使用 "sha256" 算法并且成功了,所以我认为问题一定出在他们希望我使用的算法上。

这是我用来处理 Webhook 的代码:

$headers = apache_request_headers();

$body = @file_get_contents('php://input');
$json = json_decode($body);

// Concatanate the reqired strings values
$sigString = $headers['PAYPAL-TRANSMISSION-ID'].'|'.$headers['PAYPAL-TRANSMISSION-TIME'].'|'.$json->id.'|'.crc32($body);

// Get the certificate file and read the key
$pub_key = openssl_pkey_get_public(file_get_contents($headers['PAYPAL-CERT-URL']));
$keyData = openssl_pkey_get_details($pub_key);

// check signature
if ($headers['PAYPAL-TRANSMISSION-SIG'] != hash_hmac($headers['PAYPAL-AUTH-ALGO'],$sigString,$keyData['key'])) {
    //invalid
}

我认为他们没有使用 HMAC 算法(对称),与他们在文档中所说的相反,而是 RSA(非对称)。所以你应该使用 openssl_verify 来验证签名。也许这会奏效:

//your code here...

// Get the certificate file and read the key
$pubKey = openssl_pkey_get_public(file_get_contents($headers['PAYPAL-CERT-URL']));

$verifyResult = openssl_verify($sigString, $headers['PAYPAL-TRANSMISSION-SIG'], $pubKey, 'sha256WithRSAEncryption');

if ($verifyResult === 0) {
    throw new Exception('signature incorrect');
} elseif ($verifyResult === -1) {
    throw new Exception('error checking signature');
}

//rest of the code when signature is correct...

PayPal 使用的签名算法名称可能与 PHP 使用的不同。参考openssl_get_md_methods方法获取有效的PHP签名算法。

这是最终有效的代码:

// Get the certificate file and read the key
$pubKey = openssl_pkey_get_public(file_get_contents($headers['PAYPAL-CERT-URL']));
$details = openssl_pkey_get_details($pubKey);

$verifyResult = openssl_verify($sigString, base64_decode($headers['PAYPAL-TRANSMISSION-SIG']), $details['key'], 'sha256WithRSAEncryption');

if ($verifyResult === 0) {
    throw new Exception('signature incorrect');
} elseif ($verifyResult === -1) {
    throw new Exception('error checking signature');
}

//rest of the code when signature is correct...

我需要解码 PayPal 使用 base64_decode() 发送给我的签名,出于某种原因,密钥仅在我使用 openssl_pkey_get_details()

时有效