哈希格子请求 Body Webhook
Hashing Plaid Request Body Webhook
我正在尝试验证从 Plaid 的 API 发送的 webhook。每个 webhook 请求都随 'plaid-verification' header 一起发送,这是一个 JSON Web 令牌。
验证所需的步骤是:
- 从请求中提取 JWT header
signed_jwt = eyJhbGciOiJFUzI1NiIsImtpZCI6IjZjNTUxNmUxLTkyZGMtNDc5ZS1hOGZmLTVhNTE5OTJlMDAwMSIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1OTA4ODcwMDEsInJlcXVlc3RfYm9keV9zaGEyNTYiOiJiNjNhMDdiNTQ3YjAwZjk5MjU0N2Y2YmJjOGQ5YWNjNjFhOGNjZWUxMzhiYzgyZjQ0YTZiYWEwOTY4M2E1ZDBmIn0.OOKvIihgqCj7Qrb2bmz7T3t7uK-0JyjiEqL2s1kWeJBM4MMmjaHKK8GmU_z91QolBWMzvPgs718EElY-rE3cwQ
- 在不验证签名的情况下提取 JWT header 值,如下所示:
{
"alg": "ES256",
"kid": "6c5516e1-92dc-479e-a8ff-5a51992e0001",
"typ": "JWT"
}
- 将
kid
和POST提取到/webhook_verification_key/get
POST /webhook_verification_key/get
{
"client_id": "MY_CLIENT_ID"
"secret": "MY_SECRET_ID"
"key_id": "6c5516e1-92dc-479e-a8ff-5a51992e0001"
}
响应是:
{
"key": {
"alg": "ES256",
"created_at": 1560466143,
"crv": "P-256",
"expired_at": null,
"kid": "6c5516e1-92dc-479e-a8ff-5a51992e0001",
"kty": "EC",
"use": "sig",
"x": "35lvC8uz2QrWpQJ3TUH8t9o9DURMp7ydU518RKDl20k",
"y": "I8BuXB2bvxelzJAd7OKhd-ZwjCst05Fx47Mb_0ugros"
},
"request_id": "HvfCtrDLG1ihcp7"
}
- 将
key
解释为JSON Web Key,验证JSON Web Key的签名有效,并提取payload(使用jose python库)
claims = jwt.decode(signed_jwt, key, algorithms=['ES256'])
claims = {
"iat": 1590887001,
"request_body_sha256": "b63a07b547b00f992547f6bbc8d9acc61a8ccee138bc82f44a6baa09683a5d0f"
}
- 计算请求的 SHA-256 body 并确保它匹配
claims['request_body_sha256']
:
Body 在文件中 body.json
{
"error": null,
"item_id": "yxQbxDjnD8hr69pKbQpbcKeVn3GL9QuyA7NV3",
"new_transactions": 390,
"webhook_code": "HISTORICAL_UPDATE",
"webhook_type": "TRANSACTIONS"
}
计算 body.json
的 SHA-256
f = open('body.json')
body = json.load(f)
f.close()
m = hashlib.sha256()
m.update(json.dumps(body).encode())
body_hash = m.hexdigest()
print(body_hash)
body_hash = 'efbb5274864518f7eb3834125d9bcdb95fb03066d3d1bed3ebcc6163d8dc3579'
上例中的 body 散列不等于从 Plaid 收到的 body 散列。这里有 2 个可能的问题:
- Plaid 未发送正确的 body 哈希(不太可能)
- 我用来散列 body 的散列方法与 Plaid 的方法不同
我在这里遗漏了什么吗?也许请求 body 在我这边编码不同?我在生产中使用 Node.js 和 Express,但我制作了一个 Python 脚本来遵循 Plaid 概述的方法 here,但我仍然没有得到正确的哈希值。老实说,我没有想法。
我与我们了不起的支持团队分享了这个,他们发现了问题。这似乎是空格的问题。如果您将 body.json 修改为每个新行的每个“制表符”有 2 个空格,它将生成正确的散列。
亚历克斯是对的。我最近 运行 遇到了同样的问题,确实 Plaid 确实根据制表符间距 2 散列了它们的正文。您可以使用 JSON.stringify(body, null, 2) 让一切都开心:
const happyBody = JSON.stringify(body, null, 2);
const body_hash = crypto
.createHash("sha256")
.update(happyBody)
.digest("hex");
另请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
奖励:您可以使用JSON.stringify(object, replacer, space)
美化JSON。最后一个参数的整数将决定使用多少空格,但如果你想要制表符,你可以用 "/t"
之类的东西替换它:JSON.stringify(someObject, null, "\t");
我正在尝试验证从 Plaid 的 API 发送的 webhook。每个 webhook 请求都随 'plaid-verification' header 一起发送,这是一个 JSON Web 令牌。
验证所需的步骤是:
- 从请求中提取 JWT header
signed_jwt = eyJhbGciOiJFUzI1NiIsImtpZCI6IjZjNTUxNmUxLTkyZGMtNDc5ZS1hOGZmLTVhNTE5OTJlMDAwMSIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1OTA4ODcwMDEsInJlcXVlc3RfYm9keV9zaGEyNTYiOiJiNjNhMDdiNTQ3YjAwZjk5MjU0N2Y2YmJjOGQ5YWNjNjFhOGNjZWUxMzhiYzgyZjQ0YTZiYWEwOTY4M2E1ZDBmIn0.OOKvIihgqCj7Qrb2bmz7T3t7uK-0JyjiEqL2s1kWeJBM4MMmjaHKK8GmU_z91QolBWMzvPgs718EElY-rE3cwQ
- 在不验证签名的情况下提取 JWT header 值,如下所示:
{
"alg": "ES256",
"kid": "6c5516e1-92dc-479e-a8ff-5a51992e0001",
"typ": "JWT"
}
- 将
kid
和POST提取到/webhook_verification_key/get
POST /webhook_verification_key/get
{
"client_id": "MY_CLIENT_ID"
"secret": "MY_SECRET_ID"
"key_id": "6c5516e1-92dc-479e-a8ff-5a51992e0001"
}
响应是:
{
"key": {
"alg": "ES256",
"created_at": 1560466143,
"crv": "P-256",
"expired_at": null,
"kid": "6c5516e1-92dc-479e-a8ff-5a51992e0001",
"kty": "EC",
"use": "sig",
"x": "35lvC8uz2QrWpQJ3TUH8t9o9DURMp7ydU518RKDl20k",
"y": "I8BuXB2bvxelzJAd7OKhd-ZwjCst05Fx47Mb_0ugros"
},
"request_id": "HvfCtrDLG1ihcp7"
}
- 将
key
解释为JSON Web Key,验证JSON Web Key的签名有效,并提取payload(使用jose python库)
claims = jwt.decode(signed_jwt, key, algorithms=['ES256'])
claims = {
"iat": 1590887001,
"request_body_sha256": "b63a07b547b00f992547f6bbc8d9acc61a8ccee138bc82f44a6baa09683a5d0f"
}
- 计算请求的 SHA-256 body 并确保它匹配
claims['request_body_sha256']
:
Body 在文件中 body.json
{
"error": null,
"item_id": "yxQbxDjnD8hr69pKbQpbcKeVn3GL9QuyA7NV3",
"new_transactions": 390,
"webhook_code": "HISTORICAL_UPDATE",
"webhook_type": "TRANSACTIONS"
}
计算 body.json
的 SHA-256f = open('body.json')
body = json.load(f)
f.close()
m = hashlib.sha256()
m.update(json.dumps(body).encode())
body_hash = m.hexdigest()
print(body_hash)
body_hash = 'efbb5274864518f7eb3834125d9bcdb95fb03066d3d1bed3ebcc6163d8dc3579'
上例中的 body 散列不等于从 Plaid 收到的 body 散列。这里有 2 个可能的问题:
- Plaid 未发送正确的 body 哈希(不太可能)
- 我用来散列 body 的散列方法与 Plaid 的方法不同
我在这里遗漏了什么吗?也许请求 body 在我这边编码不同?我在生产中使用 Node.js 和 Express,但我制作了一个 Python 脚本来遵循 Plaid 概述的方法 here,但我仍然没有得到正确的哈希值。老实说,我没有想法。
我与我们了不起的支持团队分享了这个,他们发现了问题。这似乎是空格的问题。如果您将 body.json 修改为每个新行的每个“制表符”有 2 个空格,它将生成正确的散列。
亚历克斯是对的。我最近 运行 遇到了同样的问题,确实 Plaid 确实根据制表符间距 2 散列了它们的正文。您可以使用 JSON.stringify(body, null, 2) 让一切都开心:
const happyBody = JSON.stringify(body, null, 2);
const body_hash = crypto
.createHash("sha256")
.update(happyBody)
.digest("hex");
另请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
奖励:您可以使用JSON.stringify(object, replacer, space)
美化JSON。最后一个参数的整数将决定使用多少空格,但如果你想要制表符,你可以用 "/t"
之类的东西替换它:JSON.stringify(someObject, null, "\t");