Node.js中Authorize.Net Webhook HMAC签名验证失败求助
核心排查与修复方案
1. 改用原始请求Body计算HMAC
Authorize.Net生成HMAC时使用的是未经过任何解析/修改的原始HTTP请求Body,而非你解析后再通过JSON.stringify()序列化的对象。解析再序列化的过程可能改变JSON的格式(比如键顺序、空格、转义符处理),直接导致签名不一致。
修改验证逻辑,直接读取原始请求体:
// Express框架下先配置获取原始body app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } })); const verifyHMAC = (rawBody, receivedHMAC) => { if (!receivedHMAC) { console.error("Received HMAC is missing."); return false; } const signatureWithoutPrefix = receivedHMAC.split("=")[1]?.trim(); if (!signatureWithoutPrefix) { console.error("Invalid HMAC format received."); return false; } console.log("Raw Body for HMAC:", rawBody.toString()); const hmac = crypto.createHmac( "sha512", // 注意:密钥解析格式需和Authorize.Net生成的匹配,见下文 Buffer.from(process.env.AUTHORIZE_NET_SIGNATURE_KEY, "utf8") ); hmac.update(rawBody); // 直接使用原始buffer更新HMAC const computedHMAC = hmac.digest("hex"); console.log("Received HMAC:", signatureWithoutPrefix); console.log("Computed HMAC:", computedHMAC); return crypto.timingSafeEqual( Buffer.from(computedHMAC, "hex"), Buffer.from(signatureWithoutPrefix, "hex") ); }; // Webhook路由中调用验证 app.post("/webhook", (req, res) => { const isValid = verifyHMAC(req.rawBody, req.headers["x-anet-signature"]); isValid ? res.sendStatus(200) : res.sendStatus(403); });
2. 确认签名密钥的解析格式
检查Authorize.Net沙箱中生成的签名密钥类型:
- 若为Base64编码,需用
Buffer.from(..., "base64")解析 - 若为普通明文字符串,直接用
utf8编码(默认值,可省略) - 仅当密钥明确是十六进制字符串时,才使用
"hex"解析
错误的编码格式会直接导致HMAC计算完全错误,这是高频踩坑点。
3. 处理100-continue预检请求
日志中出现expect: '100-continue',说明Authorize.Net会先发送预检请求,再发送实际payload:
- Express默认会自动处理该请求,若有自定义中间件,不要拦截或修改100-continue请求流程
- 确保Webhook路由仅处理POST请求,且不会在预检阶段返回错误
4. 验证Payload一致性
对比日志中输出的Payload for HMAC与ngrok请求 inspector 中显示的原始请求体:
- 检查是否存在多余转义符、空格差异
- 确认键的顺序是否一致(
JSON.stringify()可能改变键顺序,但Authorize.Net原始body的键顺序是固定的)
内容的提问来源于stack exchange,提问作者John Achero
相关产品推荐
相关产品推荐

