每日整理真实提问 356 个问题 · 726 个回答 需要系统性的技术文档?看 Shopify 技术百科 1000 篇 → 400-873-8117
已解决 提问于 18 天前

HMAC 校验一直不通过,密钥肯定是对的

2 个回答 2,828 次浏览 Webhook 与事件 最后活跃 14 天前
7

按文档用 X-Shopify-Hmac-Sha256 和 app secret 做 HMAC-SHA256 校验,算出来的值和请求头永远不等。

陈
陈工提问者
Shopify 认证开发者 · 专注主题与 Liquid
18 天前提问 · 已收到 2 个回答

2 个回答

已采纳 · 提问者确认解决
34

先把判断放在前面:九成是拿「解析后的 JSON」去算,而不是原始请求体;反序列化再序列化会改变空格与顺序。

1处理顺序

  1. 保留原始 body 字节流(await request.body() / req.rawBody),不要先 JSON.parse 再 stringify。
  2. 用 secret 作为 key、原始 body 作为 message 做 HMAC-SHA256,再 base64。
  3. 比较时用恒定时间比较函数,避免时序攻击。
  4. 确认用的是应用的 API secret,不是 Admin API token。
  5. 在中间件里做校验,别让框架的 body parser 提前消费了流。
javascript
// Node / Express:必须拿原始 body
app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
  const hmac = crypto
    .createHmac('sha256', process.env.SHOPIFY_API_SECRET)
    .update(req.body)            // Buffer,不要 toString 后重新 parse
    .digest('base64');

  const ok = crypto.timingSafeEqual(
    Buffer.from(hmac),
    Buffer.from(req.get('X-Shopify-Hmac-Sha256') || '')
  );
  if (!ok) return res.sendStatus(401);

  res.sendStatus(200);           // 先回 200,业务异步处理
  queue.push(JSON.parse(req.body.toString('utf8')));
});
验收:用真实 webhook 回放测试,校验通过率 100%,篡改 body 后校验失败。
风 风格技术团队 回答于 17 天前
14

另一个高频原因:框架默认对 body 做了 gzip 解压或字符集转换,算出来的哈希自然不同。Node 里用 express.raw({type:'*/*'}) 挂在路由前最稳。

泽 阿泽 · 前端工程师 · 16 天前

你的处理方式是什么?

写下你实际验证过的步骤,比「我也有这个问题」有用得多。当前版本为静态展示,提交后会由团队整理并回复。

描述你遇到的现象、店铺环境(主题 / 套餐 / 应用)、已经试过哪些操作……
我要单独提问 工作日 10 分钟内回复,可直接加微信 fenggejishu