微信支付计划于2018-05-29日更换服务器证书,这个通知已经N次了,一直不想整,没办法,时间快到了,得处理了。今天抽空整了下,写篇 blog 记录下:
首先看:
微信支付HTTPS服务器证书验证指引
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=23_4
我对服务器不是很了解,对证书这个东西也没了解过。打开上面的这个链接,仔细阅读,大概明白了意思。我的理解是:
『
微信支付使用HTTPS来保证通信安全,商户与微信支付服务器通信前,要在客户端的操作系统或者执行环境(如JRE等)中部署权威机构的根证书。 商户调用API的过程中,会用根证书来校验微信支付服务器及域名的真实性。
』
我们使用 curl 命令,来请求微信支付 API 时,需要通过 『 同颁发给微信HTTPS服务器的证书 的同一家权威机构』的根证书,来验证我们请求的是不是真实的微信支付服务器及域名!
所以,我们只需要下载新的根证书,然后部署到我们服务器上。curl 请求的时候,使用该证书即可!
根据指引,让我们来验证:
1.调用微信支付沙箱环境的API接口验证
微信支付新的服务器证书,部署在 '沙箱环境',所以,我们来请求沙箱环境即可。
『
这里,我给出我本次测试的代码
特殊说明:
我的系统使用的 easywechat,为了验证,我参照按照官方的 demo 里的方法,
重新写了个方法,来请求验证
』
/*
上方的相关 config 配置自己更换
*/
<?php
$sandbox_url = 'https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey';
$mch_id = config('easy_wechat.payment.merchant_id');
$key = config('easy_wechat.payment.key');
$cert_path = config('easy_wechat.payment.cert_path');
$key_path = config('easy_wechat.payment.key_path');
$nonce_str = 'pinxuejianyou';
$params = [
'mch_id' => $mch_id,
'nonce_str' => $nonce_str,
];
// 签名步骤一:按字典序排序参数
ksort($params);
$params_string = '';
foreach ($params as $k => $v)
{
if($k != 'sign' && $v != '' && !is_array($v)){
$params_string .= $k . '=' . $v . '&';
}
}
$request_params = $params_string = trim($params_string, '&');
// 签名步骤二:在string后加入KEY
$params_string .= '&key=' . $key;
// 签名步骤三:MD5加密
$params_string = md5($params_string);
// 签名步骤四:所有字符转为大写
$sign = strtoupper($params_string);
//
/*
微信请求,参数都必须是:
POST 请求
xml 格式
本次天真地以为,直接拼接为字符串,发现一直报错!(Mark 下错误)
*/
// 最终的请求地址(Mark 下错误)
// $request_url = $sandbox_url . '?' . $request_params . '&sign=' . $sign;
// 请求的 xml 参数
$request_xml = <<<EOF
<xml>
<mch_id>{$mch_id}</mch_id>
<nonce_str>{$nonce_str}</nonce_str>
<sign>{$sign}</sign>
</xml>
EOF;
// 发送请求
$ch = curl_init();
// curl 配置
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
// 最终的请求地址(Mark 下错误)
// curl_setopt($ch, CURLOPT_URL, $request_url);
curl_setopt($ch, CURLOPT_URL, $sandbox_url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);//严格校验
// 设置 header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
// 要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if(false){
// 设置证书
// 使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, $cert_path);
curl_setopt($ch,CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, $key_path);
}
// post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_xml);
$result = curl_exec($ch);
// 返回结果
if($result){
curl_close($ch);
// 解析结果
libxml_disable_entity_loader(true);
$response = json_decode(json_encode(simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
dd($response);
} else {
$error = curl_errno($ch);
curl_close($ch);
dd($error);
}
/*
重要!!
微信内部提示:
『 注意: 需要用跟生产环境相同的操作系统、执行环境、开发语言及程序逻辑进行验证。使用curl命令行工具验证成功,并不代表你的系统支持了新的服务器证书。 』
*/
意思就是:
1.即使你用我上面的方法验证成功了,也不一定百分百说明你的程序系统支持了 『新服务器证书』,还需要确保,你的服务器环境、代码环境,都必须和你线上的环境一模一样。
所以,我们其实可以直接在服务器上,使用我上面的方法,来访问下即可。(不用在你项目中的测试环境上访问)
2.即使在线上服务器上,访问可以了,我的程序的写法,还需要和你目前系统的微信 curl 请求的写法,基本吻合,不要出现一些 curl 配置不同,可能也不行(概率很小,我的系统用的 easywechat,应该也没事)
2.绑定HOST,请求已部署新证书的微信支付API服务器
vim /etc/hosts,添加
#113.96.240.139 api.mch.weixin.qq.com
#157.255.180.139 api.mch.weixin.qq.com
#121.51.30.139 api.mch.weixin.qq.com
(一般没有问题吧)
修正指引,引用 『微信支付指引』 里内容:
『
大部分情况下,验证失败都是由于以下两种情况导致的:
情况一:程序中指定了根证书,但是指定的根证书中仅包含了微信支付老的根证书。
情况二:服务器上没有新的根证书。
可通过以下两个方案修正:
方案一:删除掉指定根证书的。当不指定根证书时,程序默认会使用系统自带的根证书。绝大部分系统内置微信支付的根证书,所以删除掉指定的根证书,不会影响到你的现有业务。
方案二:更新根证书。往truststore或者根证书信任列表中追加新的根证书
推荐使用“方案一”来修正,该方案对服务器证书的兼容性更好。原因是:微信支付新的根证书分别在 2025年5月13日、2031年11月10到期。到期后,同样地要更换根证书。使用方案一修复的话,你的系统中很可能已内置了后续微信支付更换时使用的根证书,从而不受影响。如果使用方案二进行修复的话,在2025年5月13日和2031年11月10日,仍可能需安装新的根证书。
』
再解读下:
我们在 curl 时,不要设置 curl 的选项,指定一个 '根证书',例如:
CURLOPT_CAINFO
CURLOPT_CAPATH
CURLOPT_SSL_VERIFYPEER
这2个配置(除非你的系统,使用了多个不同的 CA 证书,一般应该不会有!),不指定根证书时,程序会默认使用系统的根证书。
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 替换即可
』
参考文章:
微信支付 - 微信支付HTTPS服务器证书验证指引
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=23_4
微信支付 - 协议规则
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=4_1
微信支付 - 安全规范(签名算法)
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=4_3
微信支付 - 签名校验工具
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1
其他:
https://www.easywechat.com/docs/master/zh-CN/troubleshooting
https://blog.csdn.net/mazicwong/article/details/54946952
https://blog.csdn.net/ecba1988/article/details/39204279
测试时,写验证代码时,注意:
1.微信要求的是:POST 提交,数据格式,提交和返回数据都为XML格式,根节点名为xml。
我拼接了下 get 和 post 的数据格式,死活不行!
(因为,之前一直使用的是 easywechat,或者是官方的 demo 代码,自己没写过,这次踩了一遍才出现问题)
2.对于程序中出现 'cURL error 60: SSL certificate: unable to get local issuer certificate.' 的错误:
1>上面的解决方法是一种
2>如果不需要证书验证,我们完全可以设置,不进行证书认证:
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
微信支付HTTPS服务器证书验证
最新推荐文章于 2024-07-17 18:55:11 发布