Stripe WebHook签名匹配失败问题求助
我来帮你一步步排查这个签名不匹配的问题,这种情况我之前也碰到过,常见的原因大概有这几个:
1. 确认签名密钥完全正确
一定要确保你使用的是Stripe后台Webhook端点对应的签名密钥(以whsec_开头),而不是普通的API密钥。复制密钥时要仔细核对,别多了空格、换行或者少了字符——有时候复制粘贴会带上隐形的空白字符,直接导致签名验证失败。
2. 检查请求体是否被提前修改
虽然你用了raw({ type: 'application/json' })获取req.rawBody,但要确认没有其他中间件(比如express.json())先解析了请求体。如果你的应用全局挂载了app.use(express.json()),这个中间件会先处理请求体,可能会破坏rawBody的原始字节流。
解决办法:把Webhook的路由定义在这些解析中间件之前,或者单独给这个路由禁用自动解析逻辑。
3. 验证服务器时间与Stripe的时间偏差
Stripe的签名包含时间戳,如果你的服务器时间和Stripe官方时间差超过5分钟,签名验证会直接失败。你可以:
- 先校准服务器的系统时间(优先推荐)
- 临时在
constructEvent中增加tolerance参数放宽时间限制,排查是否是时间问题:event = stripe.webhooks.constructEvent( req.rawBody, sig, stripeWebhookSigningKey, 300 // 允许5分钟的时间偏差,单位为秒 );
4. 检查签名请求头的获取是否正常
在catch块里额外打印sig的值,确认它是完整的签名字符串(格式应为t=xxx,v1=xxx,v0=xxx)。有些服务器会自动把请求头转成小写,不过stripe-signature这个键是通用的,一般不会有问题,但打印出来确认更稳妥。
5. 本地测试用Stripe CLI转发请求
如果是本地开发环境,别自己手动模拟Webhook请求——手动构造的请求体很容易和Stripe实际发送的不一致。用Stripe CLI转发事件是最靠谱的方式:
stripe listen --forward-to localhost:3000/webhook
这样Stripe会自动生成正确的签名,避免人为构造请求的误差。
另外,你的代码里catch块只打印了错误,建议额外打印sig和req.rawBody的长度(或者部分内容),能帮你更快定位是签名本身不对,还是请求体被篡改了。
内容的提问来源于stack exchange,提问作者Alk




