提问者:小点点

如何在PHP验证贝宝网络钩子签名?


我对SSL和证书不是很了解。我在PHP上用了“如何使用hash_hmac()和“SHA256withRSA”?”看看我是否可以在PayPal工作的情况下获得webhook。

我的问题是我得到以下错误后调用openssl_verify()和返回结果(0):

OpenSSL错误openssl_verify错误:04091068:rsa例程:INT_RSA_VERIFY:错误签名

我试图解决这个问题,但留档在错误和网络周围的功能是最小的。

我当前的代码如下所示:

 // get the header post to my php file by PayPal
 $headers = apache_request_headers();
 // get the body post to me php file by PayPal
 $body = @file_get_contents('php://input');
 $json = json_decode($body);

 // TransmissionId|TransmissionTimeStamp|WebhookId|CRC32 as per PayPal documentation
 $sigString = $headers['Paypal-Transmission-Id'].'|'.$headers['Paypal-Transmission-Time'].'|'.$json->id.'|'.crc32($body);

 // $headers['Paypal-Cert-Url'] contains the "-----BEGIN CERTIFICATE---MIIHmjCCBoKgAwIBAgIQDB8 ... -----END CERTIFICATE-----"
 $pubKey = openssl_pkey_get_public(file_get_contents($headers['Paypal-Cert-Url']));

 // and this is the call to verify that returns result (0)
 $verifyResult = openssl_verify($sigString, base64_decode($headers['Paypal-Transmission-Sig']), $pubKey, 'sha256WithRSAEncryption');

与我使用的参考代码唯一不同的是,我不使用openssl_pkey_get_details($pubKey),因为除了现有的签名错误之外,我还会得到以下错误:

OpenSSL错误openssl_verify错误:0906D06C:PEM例程:PEM_read_bio:无起始行OpenSSL错误openssl_verify错误:04091068:rsa例程:INT_RSA_VERIFY:错误签名

此外,我尝试了一种变体,在标头上不使用base64_decode(),但会得到相同的返回结果(0),并错误地指出:

OpenSSL错误openssl_verify错误: 04091077:rsa例程:INT_RSA_VERIFY:错误的签名长度

签名有什么问题?


共3个答案

匿名用户

您可能想要使用这段代码:

$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');
}

匿名用户

公式是

匿名用户

这可能不是您想要的,但是使用OpenSSL手动验证签名的替代方法可能是使用PayPalPHPRestfulAPI。

PayPalRestfulAPI公开了一个endpoint,允许您验证网络钩子: /v1/notifications/verify-网络钩子签名

PayPal-PHP-SDK提供了一个VerifyWebhookSignature类,可以轻松调用该终端。

他们还有一个示例脚本,说明如何使用VerifyWebhookSignature类。