微信支付HTTPS服务器证书验证指引

最后更新于:2018-05-15 23:06:56

微信支付HTTPS服务器证书验证指引

目录

1. 背景介绍

2. 常见问题

3. 验证证书

4. 修正指引

5. 其他说明

6. 联系我们

背景介绍

微信支付使用HTTPS来保证通信安全,商户与微信支付服务器通信前,要在客户端的操作系统或者执行环境(如JRE等)中部署权威机构的根证书。商户在调用API过程中,会用根证书来校验微信支付服务器及域名的真实性。

因微信支付HTTPS服务器证书的根证书将于2018年8月23日到期失效,微信支付计划于2018年5月29日, 更换服务器证书。若你的服务器上没有部署新的根证书,将可能导致你的下单、退款、企业付款等功能无法正常使用。

微信支付新的服务器证书由权威机构(DigiCert) 签发,为了提升兼容性,微信支付的服务器上同时部署了DigiCert的交叉证书,客户端仅包含以下两个根证书中的任意一个即可。

目前大部分操作系统和执行环境中已经内置了该根证书,具体兼容性列表如下:

权威机构根CA证书

证书序列号

证书有效期

Windows兼容

Java兼容

证书下载

DigiCert Global Root CA 

08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a

2006.11.10 - 2031.11.10

Windows 7+

1.6.05及以上

PEM格式

DER格式

Baltimore CyberTrust Root CA

02:00:00:b9

2000.5.13 - 2025.5.13

Windows XP及以上

1.4.2及以上

PEM格式

DER格式

常见问题

Q1:什么是微信支付HTTPS服务器证书?

A:微信支付HTTPS服务器证书是由权威机构颁发的证书。商户调用微信支付API时,能通过该证书来认证微信支付的身份。

Q2:什么是根证书?

A:权威机构用它的“私钥”来颁发服务器证书。 与“私钥”相对应的是“公钥”,“公钥”被用来认证服务器证书的真实性。权威机构的公钥会被制作成证书,简称“根证书”。

Q3:根证书和API证书是同一个吗?

A:不是,两者没有关系。

“根证书”是用来校验微信支付的域名及服务器的真实性, 通常内置在操作系统或者执行环境(如JRE等)中。

“API证书”是用来证实商户身份的,通常在调用微信支付安全级别较高的接口(如:退款、企业红包、企业付款等)时,才会使用到API证书。

Q4:微信支付为什么要更换服务器证书?

A:根证书存在有效期,根证书到期后无法继续被用来校验服务器证书。

因此,微信支付跟权威机构申请了新的服务器证书。避免在老的根证书过期后商户调用微信支付API时出现问题。

Q5:微信支付更换服务器证书需要商户配合做哪些事情?

A: 需要开发人员做以下事情:

一、验证你的系统是否支持微信支付新的服务器证书,所有涉及。具体的验证方式参考。

二、若已支持的话, 不需要做任何操作。 若不支持的话, 需要按指引排查相关原因,并升级你的系统。

注意:

a)商户按指引进行验证或自行安装证书, 不会产生任何费用。

b)商户使用的其它https证书不需要更换或者升级。 

c)商户不需要更换API证书

Q6:如果不验证,会影响下单/退款等功能吗?

A:大部分情况下,不验证根证书并不会影响下单、退款等功能。

以下两种情况肯定会影响到你的下单、退款等功能:

一、程序中指定了老的根证书

二、服务器上没有新的根证书

所以, 仍旧建议你按照指引进行验证所有正在使用的微信支付接口。

Q7:微信支付更换证书前,开发人员可以提前安装根CA证书吗?还是要微信支付更换后,再安装根CA证书?

必须提前安装,提前安装根证书不会影响正在使用的功能。

微信支付在更换换证书的过程中, 会同时使用新老两个服务器证书,商户的系统要能正常处理这种情况。 因此, 商户的服务器或者执行环境(如JRE的TrustStore等)中,至少要需要包含新老两个根证书。

验证证书

下面提供了两种方式供商户提前验证是否支持微信支付新的服务器证书。 建议商户使用方式一验证后, 再使用方式二验证确保正在使用的所有接口均不受影响。

方式一:调用微信支付沙箱环境的API接口验证

注意: 需要用跟生产环境相同的操作系统、执行环境、开发语言及程序逻辑进行验证。使用curl命令行工具验证成功, 并不代表你的系统支持了新的服务器证书。

微信支付已经将新的服务器证书部署到了沙箱域名(apitest.mch.weixin.qq.com), 由于服务器证书是支持多域名的,API域名(api.mch.weixin.qq.com)与沙箱域名(apitest.mch.weixin.qq.com)使用的是同一张证书。

API接口调用说明:

请求Url https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey
是否需要api证书
请求方式 POST
请求格式 XML

请求参数:

字段名 字段 必填 示例值 类型 说明
商户号 mch_id 1305638280 String(32) 微信支付分配的微信商户号
随机字符串 nonce_str 5K8264ILTKCH16CQ2502SI8ZNMTM67VS String(32) 随机字符串,不长于32位
签名 sign 5K8264ILTKCH16CQ2502SI8ZNMTM67VS String(32) 签名结果,详见签名生成算法

返回参数:

字段名 字段 必填 示例值 类型 说明
返回状态码 return_code SUCCESS String(16) SUCCESS/FAIL 
返回信息 return_msg 签名失败 String(128) 返回信息,如非空,为错误原因 ,签名失败 ,参数格式校验错误

以下字段在return_code 为SUCCESS的时有返回。

字段名 字段 必填 示例值 类型 说明
商户号 mch_id 1305638280 String(32) 微信支付分配的微信商户号
沙箱密钥 sandbox_signkey 013467007045764 String(32) 返回的沙箱密钥

当返回结果return_code为“SUCCESS”,说明你的系统支持新的服务器证书,反之则需要根据指引排查问题。

 

方式二:绑定HOST,请求已部署新证书的微信支付API服务器

注意:验收完成后,请及时恢复服务器上的host配置,微信支付服务器证书更新完成后,此处使用的IP会被关停。

商户可以根据不同的网络运营商, 为域名 api.mch.weixin.qq.com 配置以下HOST:

网络运营商

绑定IP

端口

电信

113.96.240.139

443

联通

157.255.180.139

443

其它(移动, 长城等)

121.51.30.139

443

HOST环境可以访问的接口与正式环境完全一致,且真实生效, 商户要评估完对业务的影响后,再进行验证。

配置完HOST后,需要逐一验证所有正在使用的微信支付接口。如果均能正常使用,说明你的系统支持新的服务器证书。反之,则需要根据指引排查问题并完成修复。

修正指引

大部分情况下, 验证失败都是由于以下两种情况导致的:

情况一、程序中指定了根证书, 但是指定的根证书中仅包含了微信支付老的根证书

情况二、服务器上没有新的根证书

可通过以下两个方案解决: 

方案一:   删除掉指定根证书的。当不指定根证书时, 程序默认会使用操作系统或者执行环境(如JRE等)中自带的根证书。微信支付会使用主流权威机构颁发的证书,权威机构的根证书在绝大部分操作系统和JRE中均已内置。 你在安装操作系统或者执行环境时, 会自动部署到对应的机器上了。 因此,删除掉指定的根证书,不会影响到你的现有业务。

方案二:   更新根证书。往truststore或者根证书信任列表中增加新的根证书接口

推荐使用”方案一”来解决,该方案对服务器证书的兼容性更好。原因是:

微信支付新的根证书分别在  2025年5月13日、2031年11月10 日到期。 到期后,同样地要更换根证书。 使用方案一修复的话,你的系统中很可能已内置了后续微信支付更换时使用的根证书,从而不受影响。

如果使用方案二进行修复的话,  在2025年5月13日和2031年11月10 日, 仍旧需要更新证书。

下面分别按照各种开发语言可能碰到的问题及解决方法: 

JAVA

可能出现的错误信息: 

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

常见原因:  代码中设置了 javax.net.ssl.trustStore 。 可以在代码中搜索关键字“trustStore” 或者 “TrustManager” 来确认

解决方法有两个, 推荐使用方法一:   删除掉指定  javax.net.ssl.trustStore 的代码  方法二:   安装根证书, 往指定的trustStore 中添加根证书.  增加安装指引的超链接

C++

可能出现的错误信息: 

cURL error 60: SSL certificate: unable to get local issuer certificate.

CURLE_SSL_CACERT (60)  peer certificate cannot be authenticated with known CA certificates.

可能原因:  代码中设置了 CURLOPT_CAINFO。 可以在代码中搜索关键字“CURLOPT_CAINFO”来确认

解决方法有两个, 推荐使用方法一:   删除掉类似  curl_easy_setopt(pCurl, CURLOPT_CAINFO,  "./rootca.pem")   的代码

方法二:   更新 rootca.pem。 用libcurl官网最新的  https://curl.haxx.se/ca/cacert.pem 替换即可 

PHP

出现的错误信息:

cURL error 60: SSL certificate: unable to get local issuer certificate.

CURLE_SSL_CACERT (60)  peer certificate cannot be authenticated with known CA certificates.

可能原因: 

使用libcurl时设置了 CURLOPT_CAINFO。 可以在代码中搜索关键字“CURLOPT_CAINFO”来确认。 

解决方法有两个, 推荐使用 方法一:   删除掉类似  curl_setopt(pCurl, CURLOPT_CAINFO,  "./rootca.pem");   的代码

方法二:   更新 rootca.pem。 用libcurl官网最新的  https://curl.haxx.se/ca/cacert.pem 替换即可 

C#

出现的错误信息:

RemoteCertificateValidationCallback 设置的回调函数返回 false 

可能原因: 

操作系统中没有新的根CA

解决方法:   安装新的根证书, 具体操作步骤见链接

Python

可能出现的错误信息: 

SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)

可能原因:  代码中用 verify 指定了根证书文件。 可以在代码中搜索关键字“verify”来确认。  类似的代码如: 

response = requests.post(

"https://api.mch.weixin.qq.com/secapi/pay/refund", 

verify="./rootca.pem",

     ……

);

解决方法有两个, 推荐使用 方法一:   删除 verify参数

方法二:   替换掉 rootca.pem。 用libcurl官网最新的  https://curl.haxx.se/ca/cacert.pem 即可 

go

错误信息:

x509: certificate signed by unknown authority .

可能原因:  发起https时, 用 RootCAs指定了根证书文件。 可以在代码中搜索关键字 “RootCAs” 来确认。  类似的代码如: 

    roots := x509.NewCertPool()

roots.AppendCertsFromPEM([]byte(rootPEM))

    tr := &http.Transport{

        TLSClientConfig: &tls.Config{RootCAs: roots},

}

    client := &http.Client{Transport: tr}

解决方法有两个, 推荐使用方法一:   删除配置项 RootCAs参数即可

方法二:   替换掉 rootca.pem。 用libcurl官网最新的  https://curl.haxx.se/ca/cacert.pem 

Ruby

可能出现的错误信息: 

SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

可能原因:  发起https时, 用 ssl_ca_file或者 cert_store 指定了根证书文件。 可以在代码中搜索关键字“ssl_ca_file” 或者 “cert_store” 来确认。  类似的代码如: 

response = RestClient::Resource.new(

"https://api.mch.weixin.qq.com/secapi/pay/refund", 

     :ssl_client_cert  =>  OpenSSL::X509::Certificate.new(File.read("./apiclient_cert.pem ")),      :ssl_client_key => OpenSSL::PKey::RSA.new(File.read("./apiclient_key.pem ")),      :ssl_ca_file => "./rootca.pem",

:verify_ssl=>OpenSSL::SSL::VERIFY_PEER).post(data);

或者

sock.cert_store.add_path('/usr/lib/ssl/certs/weixin')

sock.cert_store.add_file('/usr/lib/ssl/certs/weixin/rootca.pem')

解决方法有两个, 推荐使用方法一:   删除 ssl_ca_file及 cert_store 指定的参数

方法二:   替换掉 rootca.pem。 用libcurl官网最新的  https://curl.haxx.se/ca/cacert.pem 

NodeJs

可能出现的错误信息: 

Caught exception: Error: CERT_UNTRUSTED

可能原因: 代码中用 ca 指定了根证书文件。 可以在代码中搜索关键字“ca” 或者 “rootca” 来确认。  类似的代码如: 

const https = require('https');

const options = {

  hostname: api.mch.weixin.qq.com ',

  port: 443, 

pfx: await readFile(__dirname + `/../cert/${app}/apiclient_cert.p12`),

ca: await readFile(__dirname + `/../cert/${app}/rootca.pem`),

};

const req = https.request(options, (res) => {

  res.on('data', (d) => {

     process.stdout.write(d);

  });

});

解决方法有两个, 推荐使用方法一:   删除 ca 指定的参数

方法二:   替换掉 rootca.pem。 用libcurl官网最新的  https://curl.haxx.se/ca/cacert.pem 

其它语言

请参考对应的TLS/SSL库相关手册。

其它说明

1、为了能提前发现商户”是否会受到影响”, ”有没有完成升级”,  微信支付会提前将商户的部分请求灰度到部署了新证书的服务器上。当商户不支持新的服务器证书时,会出现错误,通常情况下重试即可恢复。在5月29号启用新的服务器证书前,微信支付会逐步提升灰度比例。

2、本次更新的根证书仅与微信支付的API接口有关, 与你使用的公众平台、开放平台等其它接口无关。

3、某些服务器或者设备上不支持多条证书信任链。如果你按照指引安装根证书DigiCert_Global_Root_CA后依然出现失败的话, 可以尝试安装根证书Baltimore_CyberTrust_Root。 也可以同时安装两个根证书,安装多个根证书并不会影响交易。

4、如果你是通过代理服务器向微信支付发起请求的话,那么需要修改代理服务器的配置。 

5、根证书升级跟服务器和应用系统相关的, 跟商户号没关系。 只要在同一台服务器升级完成后, 该服务器上使用的所有商户号都可以正常使用的。

联系我们

如果验证或者修复问题的过程中, 遇到困难,可以发送邮件到 [email protected]

文档更新时间:  2018年4月15日

内容转自微信支付 商户平台官网  开发文档 (文档内容如有更新,请以官方文档为准),链接地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=23_4