签名相关问题

更新时间:2023.04.28

# 如何在程序中加载私钥

推荐使用微信支付提供的SDK。你也可以查看下列编程语言的示例代码。

示例代码

# 1. 为什么请求返回401 Unauthorized?

请根据报文中的message信息,在下表中找到错误的原因和对应的解决方案。

错误描述 原因 解决方案
商户未设置APIv3密钥。 商户未设置APIv3密钥 请登录商户平台设置APIv3密钥
商户未申请过证书。 商户未申请过API证书 请参考什么是商户API证书?如何获取商户API证书? (opens new window)
商户证书序列号有误。 使用了错误的商户证书,或者使用了已经失效的历史的商户证书,或者获取的商户证书序列号有误 请检查商户证书,可登录
商户证书已过期。 使用了已经过期的商户证书和私钥 请到商户平台进行续期,使用续期后的新证书
商户证书已作废。 使用了商户主动作废的商户证书和私钥 请到商户平台重新申请证书后,使用新申请的证书
错误的签名,导致验签失败。 使用了错误的商户私钥,或签名串构造不正确 请见下一问题
HTTP头Authorization值格式错误 缺少 Authorization头,或其格式不正确 请检查上送的 Authorization
HTTP头Authorization认证类型不正确 不支持 Authorization中声明的签名算法 请检查上送的 Authorization,目前仅支持WECHATPAY2-SHA256-RSA2048
HTTP头Authorization中的timestamp与发起请求的时间不得超过5分钟 Authorization头中的时间戳timestamp所示时间距离当前时间超过5分钟 请检查系统时间是否准确,或者获取时间的逻辑是否正确
已更换证书,请使用新证书 商户主动重新申请了商户API证书 请使用新申请的商户API证书

# 2. 如何定位“错误的签名,导致验签失败”的错误?

为了方便商户定位签名问题,微信支付对于验签失败的请求,会在应答的错误详情detail中加入验签信息。

  • method,HTTP请求方法
  • url,请求的URL
  • truncated_sign_message,微信支付验签时使用的签名串(换行符显示成\n)。为了方便查看,我们对最后的请求报文主体做了截断
  • sign_message_length,微信支付验签时使用的签名串的字节长度
1{
2"code": "SIGN_ERROR",
3"message": "错误的签名,验签失败",
4"detail": {
5 "field": "signature",
6 "issue": "sign not match",
7 "location": "authorization",
8 "sign_information": {
9 "method": "GET",
10 "url": "/payscore/user-service-state?service_id=500001&appid=wxeaf7bf1de621b0c2&openid=oWm9Z5JQwgV7BKAQUeKsUMVSjTpQ",
11 "truncated_sign_message": "GET\n/payscore/user-service-state?service_id=500001&appid=wxeaf7bf1de621b0c2&openid=oWm9Z5JQwgV7BKAQUeKsUMVSjTpQ\n1559194069\n18a427e78d2344e1a71156a2690cc4d6\n\n",
12 "sign_message_length": 157
13 }
14}
15}

建议商户的开发者在程序中将自己组装的签名串 以及签名串的字节长度 在调试信息中输出,跟微信支付返回的验签信息进行仔细对比,排查以下几种常见的错误: 签名串的最后一行没有附加换行符

如果请求报文主体为空(如GET请求),最后一行应为一个换行符。

# 签名串中的参数,跟实际请求的参数不一致

  • 手工拼接的URL,和实际请求发送的不一致。我们建议的实现是,使用HTTP库构造请求对象或者URL对象,再使用相应的方法取得URL。
  • 签名和设置Authorization头时,使用了前后生成的两个时间戳。
  • 签名和设置Authorization头时,使用了前后生成的两个不同的随机串。
  • 签名和请求时,使用了前后两次序列化的JSON串作为请求主体。

注意

商户的开发者可以将关键参数生成并保存在变量中,签名和发送请求时统一使用,避免前后生成的信息不一致。

# 文本的编码不一致

生成签名串使用了非UTF-8编码或者未设置具体编码。

# 构建签名串顺序不对

构建签名串没有按照文档要求的顺序进行构建。

# 使用了错误的商户私钥

开发者可以使用如下的openssl命令检查私钥和商户证书中的modulus(p、q两个大素数的乘积)是否一致。如果两者一致,那么私钥和证书是成对的。

1$ openssl x509 -noout -modulus -in 1900009191_20180326_cert.pem
2Modulus=C6D43C87B991...
3$ openssl rsa -noout -modulus -in 1900009191_20180326_key.pem
4Modulus=C6D43C87B991...

注意

  1. modulus长度为2048位,输出为512个字节。
  2. 检查密钥匹配前,请先查看证书序列号,检查是否是正确的商户证书。

# 3. 为什么微信支付的回调缺少签名的几个HTTP头?

微信支付的回调,在HTTP头部包含了以下四个HTTP头:

  • Wechatpay-Timestamp
  • Wechatpay-Nonce
  • Wechatpay-Signature
  • Wechatpay-Serial

某些代理服务器或CDN服务提供商,转发时会“过滤”微信支付扩展的HTTP头,会导致验签的应用层无法取到微信支付的签名信息。遇到这种情况时,建议商户调整代理服务器配置,或者通过直连的方式接受微信支付的回调。