如何验证 PayPal Webhook 签名?
Posted
技术标签:
【中文标题】如何验证 PayPal Webhook 签名?【英文标题】:How to verify PayPal Webhook signature? 【发布时间】:2020-08-22 09:26:49 【问题描述】:无法验证从 PayPal 收到的 Webhook。可用的示例不多,并且集成商没有足够的加密知识来完成任务。
遵循的指南是Webhook notifications。
不知道sn-p代码有什么问题,结果总是假的。
调用notifications/verify-webhook-signature端点也会导致错误。
/// <summary>Verify PayPal Webhook Signature</summary>
/// <param name="webhookId">0YF54686R9851380C</param>
/// <param name="transmissionId">785bc690-901d-11ea-8fc5-17f05150a6df</param>
/// <param name="transmissionTime">2020-05-07T04:44:33Z</param>
/// <param name="certUrl">https://api.sandbox.paypal.com/v1/notifications/certs/CERT-.....</param>
/// <param name="transmissionSignature"></param>
/// <param name="webHookEvent">"\"id\":\"WH-5P8216093E7920426-60J97470GW748563B\",\"create_time\":\"2020-05-07T11:43:48.000Z\",....</param>
private static void VerifyWebhookSignature(string webhookId, string transmissionId, string transmissionTime,
string certUrl, string transmissionSignature, string webHookEvent)
Crc32 crc32 = new Crc32();
String hash = string.Empty;
var arrayOfBytes = Encoding.UTF8.GetBytes(webHookEvent);
foreach (byte b in crc32.ComputeHash(arrayOfBytes)) hash += b.ToString("x2").ToLower();
string expectedSignature = String.Format("0|1|2|3", transmissionId,
transmissionTime, webhookId, hash);
string certData = new System.Net.WebClient().DownloadString(certUrl);
X509Certificate2 cert = new X509Certificate2(Encoding.UTF8.GetBytes(certData));
try
byte[] signature = Convert.FromBase64String(transmissionSignature);
byte[] expectedBytes = Encoding.UTF8.GetBytes(expectedSignature);
using (RSA rsa = cert.GetRSAPublicKey())
var verified = rsa.VerifyData(
expectedBytes,
signature,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
Console.WriteLine($"Verified: verified");
catch (Exception ex)
throw;
【问题讨论】:
使用编码 utf-8 instread of ascii。 ASCII 编码会删除不可打印的字符。如果这不起作用,我怀疑 key 的填充模式也可能是一个问题。你遇到了什么错误?请参阅:google.com/… 没有错误,只是没有验证。我相信上面的代码中使用了 UTF-8 编码。我们也将填充切换为 Pss,结果相同。我们用来测试的数据来自一个真实的 Webhook 事件,测试是在 Webhook 被触发时完成的,所以理论上我们应该能够验证它。 如果你使用了无效的密钥,你会得到一个异常。此外,如果您使用了错误的加密模式,您会遇到异常。所以我认为用于加密的密钥不是你用来解密的。确保密钥和数据正确。一个字节,你不会得到正确的结果。 【参考方案1】:我可以确认您的实现工作正常,但是我不确定您使用哪种实现来计算 CRC32 校验和。当使用Crc32.NET 时,以下 sn-p 就足够了:
var arrayOfBytes = Encoding.UTF8.GetBytes(webHookEvent);
string hash = Crc32Algorithm.Compute(arrayOfBytes).ToString();
感谢您在这里提供它,我也在努力寻找一个可行的例子!
PS:刚刚在这里发现了官方实现:https://github.com/paypal/PayPal-NET-SDK/blob/master/Source/SDK/Api/WebhookEvent.cs#L156
【讨论】:
以上是关于如何验证 PayPal Webhook 签名?的主要内容,如果未能解决你的问题,请参考以下文章
验证模拟 PayPal webhook 的签名总是返回“FAILURE”
node.js 中 PayPal webhook 的签名是啥?