wechatpay-apiv3 / wechatpay-php

微信支付 APIv3 的官方 PHP Library,同时也支持 APIv2
Apache License 2.0
475 stars 98 forks source link

对APIv3强制验签逻辑进行优化,对已知无签返回的请求,自动忽略验签 #94

Closed TheNorthMemory closed 2 years ago

TheNorthMemory commented 2 years ago

运行环境

- wechatpay-php: 1.4.4

描述你的问题现象

需求

引申自 #92 , 当前已知在 APIv3 的三个接口上,有三种“特殊”逻辑,当前版本SDK并没有特殊处理,如下:

1. 国内商户客诉图片下载

URL: /v3/merchant-service/images/{slot}

接口本身返回的流stream,无验签逻辑;

2. 国内商户账单下载

URL: /v3/billdownload/file

接口本身返回的流stream,验签逻辑依赖前置请求账单的SHA1摘要,而前置接口的返回的SHA1值,已按标准RSA公钥逻辑验签;

3. 海外商户账单下载

URL: /hk/v3/statements

请求的返回值,签名含两种逻辑,标准RSA公钥验签逻辑注1及流stream SHA1摘要逻辑;

注1: 验签的是 SHA1 摘要的JSON表达式,而非流,与标准RSA公钥验签验证返回BODY不同;

分析

  1. 第1种情形,接口设计的比较另类另说(见 #85 ),无验签逻辑需要客户端自动忽略;

  2. 第2种是两步请求分开验签,先RSASHA1,验签逻辑含上下文context语境,后置的客户端本地验签逻辑可循 以函数链的形式流式下载交易帐单 示例,在 ->then 链上处理,当前请求返回值无明确签名,客户端需要忽略验签;

  3. 第3种情形可以看作是第2种的特例,一步请求,接口即回吐了RSA签名又包含SHA1摘要,客户端设计可以仿第2种逻辑,仅对RSA签名部分进行验签,保证当前请求的返回值,是来自平台RSA私钥数据签名注2SHA1摘要逻辑交由客户端本地在 ->then 链上自行比对摘要值;

注2: 按照规范,非对称加密的公钥是公开的,可任意发行的,而平台RSA私钥是私密数据,一次请求即含签名又含摘要,虽然任何人(持有效公钥)都可以验签,但RSA签名值本身是不可伪造,是安全的。

改进

按照上述分析,对前两种接口设计,当次请求/响应需要忽略RSA验签;对第三种逻辑,需要构造一个本地摘要值JSON串,做一次RSA公钥验签,验签若失败,则按当前处理逻辑抛\GuzzleHttp\Exception\RequestException异常;RSA验签成功则(忽略SHA1值比对逻辑)放行。