微信支付回调后如何验证签名是否合法?

玉轩 阅读 46

我接入了微信H5支付,用户支付完成后微信会跳转回我的return_url,但我不确定怎么验证这个回调是不是真的来自微信,防止伪造请求。官方文档说要用签名验证,但我试了几次总是验签失败。

我用的是微信提供的验签方法,把参数按字典序排序后拼接,再用商户APIv3密钥做HMAC-SHA256。但返回的sign和我算出来的不一样。是不是我漏了什么参数?比如要不要包含sign_type?

这是我的验签代码:

function verifyWechatSignature(params, expectedSign) {
  const { sign, ...rest } = params;
  const sortedKeys = Object.keys(rest).sort();
  const queryString = sortedKeys.map(k => <code>${k}=${rest[k]}</code>).join('&');
  const computedSign = crypto
    .createHmac('sha256', WECHAT_APIV3_KEY)
    .update(queryString)
    .digest('hex')
    .toUpperCase();
  return computedSign === expectedSign;
}

每次算出来的computedSign和params.sign都不一样,到底哪里出错了?

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
程序员世豪
你漏了最关键的一步:微信回调的签名是用整个HTTP body计算的,不是URL参数。而且body需要先转JSON再处理。给你个能跑通的代码:

const verifyWechatCallback = (body, signature, apiv3Key) => {
// 微信通知的签名是整个body的HMAC-SHA256
const serializedBody = JSON.stringify(body);
const computedSign = crypto
.createHmac('sha256', apiv3Key)
.update(serializedBody)
.digest('hex')
.toUpperCase();

return computedSign === signature;
};

// 用法示例
const isValid = verifyWechatCallback(
req.body,
req.headers['wechatpay-signature'],
process.env.WECHAT_APIV3_KEY
);


几个关键点:
1. 签名计算的是原始JSON body,不是URL参数
2. 微信回调的签名在header里叫wechatpay-signature
3. 记得要用商户平台的APIv3密钥,不是API密钥

微信文档这里确实容易踩坑,我当初也折腾了半天。你复制过去试试,应该就没问题了。
点赞 1
2026-03-08 04:00
♫雯清
♫雯清 Lv1
你用错密钥了,H5支付回调验签用的是商户APIv2密钥(32位字符串),不是APIv3密钥;而且参数排序后拼接时,不包含 sign 字段,也不包含 sign_type 字段,拼接完再做 HMAC-SHA256。懒人方案直接上代码:

function verifyWechatSignature(params, expectedSign) {
const { sign, sign_type, ...rest } = params;
const sortedKeys = Object.keys(rest).sort();
const queryString = sortedKeys
.map(k => ${k}=${rest[k]})
.join('&');
const computedSign = crypto
.createHmac('sha256', WECHAT_APIV2_KEY)
.update(queryString)
.digest('hex')
.toUpperCase();
return computedSign === expectedSign;
}


记得把 WECHAT_APIV2_KEY 换成你在微信商户平台配置的 APIv2 密钥(不是 APIv3 的那个)。
点赞 3
2026-02-26 18:00