Node.js Express中Shopify Webhook完整性校验失败求助
我来帮你梳理下这个问题的排查方向,你遇到的情况其实在Express环境里挺常见的,咱们一步步来定位:
先确认
req.rawBody是否是真正的原始请求体
Express默认会用中间件解析请求体,如果你已经加了express.json()或者body-parser,那req.rawBody很可能已经被修改甚至不存在了。正确的做法是在解析中间件里保留原始内容,比如用body-parser的verify选项:const bodyParser = require('body-parser'); app.use(bodyParser.json({ verify: (req, res, buf) => { req.rawBody = buf; // 直接存Buffer,不要转字符串,避免编码问题 } }));另外,你之前把
req.rawBody转成JSON.stringify再处理是错误的!Shopify的HMAC签名是基于原始请求体的字节内容计算的,不是JSON序列化后的字符串——原始请求里的空格、换行符和序列化后的可能不一样,这直接导致签名不匹配。检查你的
APP_SHARED_SECRET是否正确
一定要确认你用的是Shopify后台对应App的Shared Secret,不是API Key或者Access Token。这个密钥在Shopify Partner Dashboard的App设置里,复制的时候别多了空格、换行或者少了字符,大小写完全敏感。校验请求头的获取是否正确
Shopify的签名头是X-Shopify-Hmac-Sha256,注意HTTP请求头在Express里会被转成小写,所以你要通过req.headers['x-shopify-hmac-sha256']来获取,别拼写错了。另外要确保没有代理或者中间件篡改了这个头的值。修正HMAC计算的代码逻辑
正确的计算应该直接用原始请求体的Buffer,不需要额外的转换,而且要用timingSafeEqual来做安全的签名对比(避免时序攻击):const crypto = require('crypto'); const validateWebhook = (req) => { const shopifyHmac = req.headers['x-shopify-hmac-sha256']; const hmac = crypto.createHmac('sha256', APP_SHARED_SECRET); hmac.update(req.rawBody); // 直接用原始的Buffer const digest = hmac.digest('base64'); return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(shopifyHmac)); };用命令行辅助测试
你可以用Shopify后台的Webhook测试工具发送一个测试请求,然后把req.rawBody保存成本地文件,用命令行计算HMAC,对比和Shopify返回的签名是否一致:cat raw-body.txt | openssl dgst -sha256 -hmac "你的Shared Secret" -binary | base64如果命令行计算的结果和Shopify的签名一致,但代码里的不一样,那肯定是代码里处理
req.rawBody的环节出了问题。
内容的提问来源于stack exchange,提问作者user269867

