签名相关问题

更新时间:2023.04.28

# 如何在程序中加载私钥

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

示例代码

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

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

错误描述 原因 解决方案
商户未设置APIv3密钥。 商户未设置APIv3密钥 请登录商户平台设置APIv3密钥
商户未申请过证书。 商户未申请过API证书 请参考什么是商户API证书?如何获取商户API证书? (opens new window)
商户证书序列号有误。 使用了错误的商户证书,或者使用了已经失效的历史的商户证书,或者获取的商户证书序列号有误 请检查商户证书序列号,登录商户平台【API安全】->【API证书】->【查看证书】,可查看商户API证书序列号。
商户证书已过期。 使用了已经过期的商户证书和私钥 请到商户平台重新申请证书后,使用新申请的证书
商户证书已作废。 使用了商户主动作废的商户证书和私钥 请到商户平台重新申请证书后,使用新申请的证书
错误的签名,导致验签失败。 使用了错误的商户私钥,或签名串构造不正确 请见下一问题
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头,会导致验签的应用层无法取到微信支付的签名信息。遇到这种情况时,建议商户调整代理服务器配置,或者通过直连的方式接受微信支付的回调。