校验webhook签名
概述
Webhook是一种用于接收实时事件通知的机制,用于将数据传输给您的应用程序。在我们发送webhook通知时,报头中会包含一个签名,以确保通知的完整性和来源的可信度
签名头
在每个事件通知中,报头中的签名Signature
包含一个时间戳和签名。
时间戳以 t=
为前缀,签名以v1
为前缀。
示例:
Signature:t=1492774577,v1=6fdfb9c357542b8ee07277f5fca2c6f728bae2dce9be2f91412f4de922c1bae4
Webhook密钥
对于每一个事件通知,会生成一个唯一密钥:whsec_
。
在验证签名前,你需要检索您的webhook密钥,您可以在webhook对象中的secret字段中提取到。
验证您的签名
通过比对报头中的签名和本地签名,您可以检验签名是否通过我们发出的。
根据下方的指南,一步一步的来检验您的签名。
步骤一:从签名头中提取时间戳和签名
您可以用,
作为分隔符,拆分并提取签名的元素。然后用=
号来连接元素的前缀和值。
提取后,前缀t
对应的值是时间戳,v1
对应的是签名。
示例如下:
t=1687845304,v1=6fdfb9c357542b8ee07277f5fca2c6f728bae2dce9be2f91412f4de922c1bae4
步骤二:准备 signed_payload
字符串
signed_payload
字符串是通过连接以下内容创建的:
- 时间戳(字符串形式)
- 字符
.
- 实际的 JSON 有效载荷(即,请求体)
您可以参考下方的形式,来准备好**signed_payload
** 字符串
1687845304
+.
+JSON payload
1687845304.{
"id": "evt_1NNUrjL6kclEVx6Mb1x5dKJ3",
"object": "event",
"api_version": "2022-11-15",
"created": 1687845303,
"data": {
"object": {
"id": "prod_O9oUVgsSaordCT",
"object": "product",
"active": true,
"livemode": true,
"name": "test",
"type": "service",
"livemode": true,
"pending_webhooks": 1,
"type": "product.created"
}
步骤三:生成本地签名
用 SHA256 散列函数计算 HMAC字符。
- 您可以在webhook对象中的
webhook.secret
得到您webhook的密钥。这个whsec_
将作为生成 HMAC字符的Key - 用您在步骤二中准备好的
signed_payload
字符串生成 HMAC字符的Message
您可以通过Key + Message, 在SHA256 散列函数得到一串HMAC字符,即您的本地签名。
示例如下:
public static void main(String[] args) {
String webhookSecret = "whsec_261V2mfsXt1BsOjJbHaQOxnTzhWZKrUE";
String timestamp = "1687845304";
String requestBody = "{\"id\":\"evt_1NNUrjL6kclEVx6Mb1x5dKJ3\",\"object\":\"event\",\"api_version\":\"2022-11-15\",\"created\":1687845303,\"data\":{\"object\":{\"id\":\"prod_O9oUVgsSaordCT\",\"object\":\"product\",\"active\":true,\"livemode\":true,\"name\":\"test\",\"type\":\"service\",\"livemode\":true,\"pending_webhooks\":1,\"type\":\"product.created\"}";
String signedPayload = timestamp+"."+requestBody;
String sha256 = hmacSha256(webhookSecret,signedPayload);
String signature = "t="+timestamp+",v1="+sha256;
}
/**
* HMAC-SHA256 签名算法
*/
public static String hmacSha256(String secret, String message) {
String res;
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKey secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
mac.init(secretKey);
byte[] hash = mac.doFinal(message.getBytes());
res = Hex.encodeHexString(hash);
} catch (Exception e) {
return null;
}
return res;
}
步骤四:对比本地签名和报头中的签名
将本地签名和报头中的签名进行比较。进行相等匹配的校验,计算webhook对象中created
对应的时间戳和报头中的签名中时间戳之间的差值,然后判断差值是否在您的容差范围内。
为了防止时序攻击,请使用常量时间字符的比较方式将本地签名与收到的报头中的签名比对校验。
Last modified: 5 个月前