wechatpay-php
wechatpay-php copied to clipboard
不恰当的使用Rsa::decrypt函数(使用OPENSSL_PKCS1_PADDING填充方案),可能引起应用层存在被攻击的风险
运行环境
- OS:MacOS
- PHP: 8.3.7
- wechatpay-php: 1.4.9
描述你的问题现象
这可能不应该是件公开讨论的事宜,有关应用安全的问题可能需要具有专业知识的人来共同探讨,然而此问题在开源社区有了许多公开讨论,暂且先把问题及可能的解决方案记录于此。
缘由
在例行性更新本地PHP版本的时候,按操作习惯,会run
一遍测试用例,然而有许久如下测试用例有一条F一直悬而未决:
https://github.com/wechatpay-apiv3/wechatpay-php/blob/2cabc8a15136050c4ee61083cd24959114756a03/tests/Crypto/RsaTest.php#L307-L321
现状
翻阅了PHP的更新历史及OpenSSL的更新历史,发现如下两条重要更新:
- Use EVP_PKEY API for openssl_public_encrypt/private_decrypt
- Make RSA decryption API safe to use with PKCS#1 v1.5 padding
PHP自8.1.0起,使用了OpenSSL的EVP_PKEY API
,且OpenSSL自3.2.0起,已显式调整EVP_PKEY_decrypt
处理逻辑,默认当填充方式为RSA_PKCS1_PADDING
解密失败时,不再抛异常,代为输出为随机字符串。这即是 "encrypted as OPENSSL_PKCS1_OAEP_PADDING, and decrpted as OPENSSL_PKCS1_PADDING" 用例测试未通过的原因所在。
公开的CVE/patch/backport如:
- Golang: Vulnerability Report: GO-2023-2375
- Ubuntu: Implicit rejection of PKCS#1 v1.5 RSA
- Python: CVE-2020-25658 - Bleichenbacher-style timing oracle
都提到了一点是,RSAES-PKCS1-v1_5
已不再安全并且容易受到攻击。
受影响
目前已知在微信支付海外版,有如下两个接口声明的非对称加密方案为RSAES-PKCS1-v1_5
:
• 使用微信支付平台证书的公钥,对于需要加密的参数值进行 RSA 加密。填充方案使用
RSAES-PKCS1-v1_5
。
1、Perform the RSA encryption for the parameter values with the public key of the WeChat Pay Platform certificate. Use
RSAES-PKCS1-v1_5
as the filling scheme.
解决方案
服务端
建议微信支付团队,评估影响等级及寻求解决方案。
客户端
本SDK(wechatpay-php)自1.2.1起,提供了OPENSSL_PKCS1_PADDING
加解密支持,目前客户端暂时未发现使用OPENSSL_PKCS1_PADDING
解密的场景,出于兼容性及安全考虑,需要:
- 调整
\WeChatPay\Crypto\Rsa::decrpt
函数,当使用OPENSSL_PKCS1_PADDING
填充方案时,给予废弃及安全提示,不再推荐使用; - 尝试兼容PHP低版本的ext-openssl(OpenSSL<3.2.0)解密失败抛异常行为,与
OpenSSL>3.2.0
默认行为保持一致,代为输出为随机字符串; - 基于以上两点,修正
WeChatPay\Tests\Crypto\RsaTest::testCrossEncryptDecryptWithDifferentPadding
用例覆盖;