Zoho 订阅验证 webhook 签名 NodeJS
Zoho subscription validate webhook signature NodeJS
我正在尝试保护我的 Zoho webhook 实施。我遵循了这个文档:https://www.zoho.com/subscriptions/kb/webhooks/securing-webhooks.html
我不太清楚该怎么做,但我很确定最后我还是按照他们说的去做了。
我没有任何查询参数。
格式只是默认 JSON 有效负载 NO X-WWW-FORM-URLENCODED.
我尝试使用以下代码,但没有得到正确的哈希值。还不清楚我是否应该对默认负载进行排序。根据 this 回答,只有表单 url 编码和查询参数是必需的,但对于普通 JSON 有效负载不需要处理。无论哪种方式,我都尝试了以下实现方式:
function computeZohoSignature(query, payload) {
return crypto
.createHmac('sha256', process.env.ZOHO_WEBHOOK_SECRET)
.update(JSON.stringify(payload), 'utf8')
.digest('hex');
}
function validSignature(signatureHash, computedHash) {
return signatureHash.length === computedHash.length
&& crypto.timingSafeEqual(Buffer.from(signatureHash), Buffer.from(computedHash));
}
我还尝试使用以下函数包装有效载荷:
function sortObjectByKeys(object) {
if (!isObject(object)) return object;
const sortedObj = {};
Object
.keys(object)
.sort()
.forEach((k) => {
sortedObj[k] = sortObjectByKeys(object[k]);
});
return sortedObj;
}
排序正确,我什至尝试只对 "root-keys" 进行排序。不管我尝试什么,哈希值都不一样。是的,我 100% 确定这个秘密是正确的,我检查了三次。
有没有人看到这里出了什么问题,或者有一个有效的 NodeJS 实现来执行此操作?
提前致谢!
典型的 Express
设置使用以下配置进行解析:
app.use(bodyParser.json());
此解析器会将请求的 body 的 parsed (object) 内容添加到请求的 body
属性路由处理程序的第一个 req
参数 (req, res) => { ... }
.
但是,您的 webhook 的哈希值是根据 raw(字符串)有效负载计算的。虽然您可以使用 JSON.stringify
将已解析的 body 转换回字符串,但这可能会导致与原始原始负载不一致。
例如,如果您的货币是 Euro
,Zoho 将传递编码的 "\u20a"
作为 currency_symbol
的值。但是,如果您使用 JSON.stringify
将已解析的 body 转换回字符串,您会发现它生成的是未编码的 "€"
。因为这导致两个字符串不相同,所以它们不会产生相同的散列。
如果不直接访问原始 body,很难准确地检测到原始原始 body 与您的 JSON.stringify
结果之间的区别,以及如何后者应该转换为与原始原始 body 相同的格式。克服这个问题的最简单方法是使用解析器的 verify
方法,将原始 body 添加到例如。路由处理程序的第一个 req
参数的 rawBody
属性,如 in this article 所述:
app.use(bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf
}
}))
如果您将 req.rawBody
的值分配给 payload
,您的 computeZohoSignature
方法生成的散列现在应该与 Zoho!
传递的签名相对应
我正在尝试保护我的 Zoho webhook 实施。我遵循了这个文档:https://www.zoho.com/subscriptions/kb/webhooks/securing-webhooks.html
我不太清楚该怎么做,但我很确定最后我还是按照他们说的去做了。
我没有任何查询参数。 格式只是默认 JSON 有效负载 NO X-WWW-FORM-URLENCODED.
我尝试使用以下代码,但没有得到正确的哈希值。还不清楚我是否应该对默认负载进行排序。根据 this 回答,只有表单 url 编码和查询参数是必需的,但对于普通 JSON 有效负载不需要处理。无论哪种方式,我都尝试了以下实现方式:
function computeZohoSignature(query, payload) {
return crypto
.createHmac('sha256', process.env.ZOHO_WEBHOOK_SECRET)
.update(JSON.stringify(payload), 'utf8')
.digest('hex');
}
function validSignature(signatureHash, computedHash) {
return signatureHash.length === computedHash.length
&& crypto.timingSafeEqual(Buffer.from(signatureHash), Buffer.from(computedHash));
}
我还尝试使用以下函数包装有效载荷:
function sortObjectByKeys(object) {
if (!isObject(object)) return object;
const sortedObj = {};
Object
.keys(object)
.sort()
.forEach((k) => {
sortedObj[k] = sortObjectByKeys(object[k]);
});
return sortedObj;
}
排序正确,我什至尝试只对 "root-keys" 进行排序。不管我尝试什么,哈希值都不一样。是的,我 100% 确定这个秘密是正确的,我检查了三次。
有没有人看到这里出了什么问题,或者有一个有效的 NodeJS 实现来执行此操作?
提前致谢!
典型的 Express
设置使用以下配置进行解析:
app.use(bodyParser.json());
此解析器会将请求的 body 的 parsed (object) 内容添加到请求的 body
属性路由处理程序的第一个 req
参数 (req, res) => { ... }
.
但是,您的 webhook 的哈希值是根据 raw(字符串)有效负载计算的。虽然您可以使用 JSON.stringify
将已解析的 body 转换回字符串,但这可能会导致与原始原始负载不一致。
例如,如果您的货币是 Euro
,Zoho 将传递编码的 "\u20a"
作为 currency_symbol
的值。但是,如果您使用 JSON.stringify
将已解析的 body 转换回字符串,您会发现它生成的是未编码的 "€"
。因为这导致两个字符串不相同,所以它们不会产生相同的散列。
如果不直接访问原始 body,很难准确地检测到原始原始 body 与您的 JSON.stringify
结果之间的区别,以及如何后者应该转换为与原始原始 body 相同的格式。克服这个问题的最简单方法是使用解析器的 verify
方法,将原始 body 添加到例如。路由处理程序的第一个 req
参数的 rawBody
属性,如 in this article 所述:
app.use(bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf
}
}))
如果您将 req.rawBody
的值分配给 payload
,您的 computeZohoSignature
方法生成的散列现在应该与 Zoho!