【发布时间】:2020-11-02 08:05:05
【问题描述】:
集成 Paypal 的智能按钮后,我无法验证 Paypal 发送的 webhook 通知。我发现的示例要么已经过时,要么不起作用。
有没有办法验证 webhook 通知,最好是 DIY 方式(即无需使用庞大而复杂的 Paypal API)?
【问题讨论】:
标签: php paypal paypal-webhooks
集成 Paypal 的智能按钮后,我无法验证 Paypal 发送的 webhook 通知。我发现的示例要么已经过时,要么不起作用。
有没有办法验证 webhook 通知,最好是 DIY 方式(即无需使用庞大而复杂的 Paypal API)?
【问题讨论】:
标签: php paypal paypal-webhooks
对此做出响应以节省潜在的麻烦,但上述示例不起作用,因为需要将身份验证令牌与您对证书文件“file_get_contents($header['Paypal-Cert-Url'])”的获取请求一起发送将无法单独工作。
只需在标头中包含您的身份验证令牌即可。
【讨论】:
据我所知,此代码只是实际有效的代码。我在堆栈溢出中发现的所有其他示例都不起作用,因为在编写签名字符串时,它们没有传递 webhook 本身 的 ID,而是使用 webhook 事件的 ID,因此验证将失败。
在 Paypal 的开发人员后端添加 webhook 后,将生成 webhook ID。创建 webhook 后,您将在已安装的 webhook 列表中看到它的 id。
剩下的很简单:我们获取标头和 HTTP 正文,并使用 Paypal 的配方组成签名:
为了生成签名,PayPal 将这些签名连接并分开 带有竖线 (|) 字符的项目。
“这些项目”是:传输 id、传输日期、webhook id 和 HTTP 正文上的 CRC。前两个可以在请求的header中找到,开发者后端的webhook id(当然那个id永远不会改变),CRC计算如下图。
证书的位置也在标头中,因此我们加载它并提取私钥。
最后要注意的是:Paypal 提供的算法名称(同样在标头字段中)与 PHP 所理解的不完全相同。 Paypal 将其称为“sha256WithRSA”,但 openssl_verify 将期望“sha256WithRSAEncryption”。
// get request headers
$headers=apache_request_headers();
// get http payload
$body=file_get_contents('php://input');
// compose signature string: The third part is the ID of the webhook ITSELF(!),
// NOT the ID of the webhook event sent. You find the ID of the webhook
// in Paypal's developer backend where you have created the webhook
$data=
$headers['Paypal-Transmission-Id'].'|'.
$headers['Paypal-Transmission-Time'].'|'.
'[THE_ID_OF_THE_WEBHOOK_ACCORDING_TO_DEVELOPER_BACKEND]'.'|'.
crc32($body);
// load certificate and extract public key
$pubKey=openssl_pkey_get_public(file_get_contents($headers['Paypal-Cert-Url']));
$key=openssl_pkey_get_details($pubKey)['key'];
// verify data against provided signature
$result=openssl_verify(
$data,
base64_decode($headers['Paypal-Transmission-Sig']),
$key,
'sha256WithRSAEncryption'
);
if ($result==1) {
// webhook notification is verified
...
}
elseif ($result==0) {
// webhook notification is NOT verified
...
}
else {
// there was an error verifying this
...
}
【讨论】: