← 中文资源

简体中文版本

排查 Webhook HMAC 签名不匹配

比对用于签名的原始字节与实际收到的字节,发现重新序列化与编码导致的签名漂移。

阅读英文原文

目标

带签名的 Webhook 只在载荷含非 ASCII 字符时校验失败,指向编码问题。本配方在任何 JSON 解析之前保存原始请求字节,用原始字节计算 HMAC,并用 timingSafeEqual 比较,同时校验时间戳容差以抵御重放,从而定位是解析改写还是代理重编码导致的失败。

步骤要点

  1. 在 JSON 解析之前保留原始字节并计算 HMAC。
  2. 用 timingSafeEqual 做常量时间比较。
  3. 校验时间戳容差,拒绝超过五分钟的重放。
  4. 确认代理没有改写请求体字节。
app.use('/webhook', express.raw({ type: '*/*' }));
app.post('/webhook', (req, res) => {
  const mac = crypto.createHmac('sha256', secret).update(req.body).digest('hex');
  const ok = crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(req.get('x-signature') || ''));
  res.status(ok ? 200 : 401).end();
});

排错提示

  • 代理可能改写字节,需保证处理器拿到原始字节。
  • 非 ASCII 载荷必须对字节缓冲而非重序列化字符串计算签名。
  • 时间戳容差需兼顾重放防护与时钟偏移。

适用边界

  • 需要访问原始请求字节。
  • 不覆盖非对称签名方案。