为什么 express.json 会影响验签

HMAC 针对字节计算。JSON 的空格、换行、转义和键顺序发生变化,都会得到完全不同的签名。业务代码可以使用解析后的对象,但签名计算必须使用解析前的 Buffer。

使用 verify 回调保存 Buffer

app.use(express.json({
  verify: (req, _res, buffer) => {
    req.rawBody = Buffer.from(buffer);
  },
}));

app.post("/webhooks/github", (req, res) => {
  verifyGitHubSignature(req.rawBody, req.headers);
  // 验签通过后再使用 req.body
  res.sendStatus(200);
});

如果只需要在部分路由保留 Body,也可以把专用中间件挂载在 Webhook 路由之前,避免为所有 API 长期保存原始内容。

上线检查清单

  • 限制请求体大小,避免超大 Payload。
  • 先验签、后解析和处理业务。
  • 使用恒定时间比较函数。
  • 快速返回 2xx,把耗时业务放入队列。
  • 使用事件 ID 实现幂等,防止重复处理。