minibear2021 / wechatpayv3

微信支付 API v3 Python SDK
MIT License
879 stars 136 forks source link

微信支付回调函数验证签名不正确,求助! #5

Closed carter8225 closed 3 years ago

carter8225 commented 3 years ago

你好,

在回调地址notify_url中接受request.header和request.body,并传入wxpay.decrypt_callback函数验证签名和解密返回值,验证签名失败,但解密返回值正确。

服务器为centos 7,已设置平台证书路径为“\cert”,运行decrypt_callback函数时,系统已下载签名并存放到该文件夹。verify(timestamp, nonce, body, signature, certificate)时可以通过该证书生成公钥文件:<cryptography.hazmat.backends.openssl.rsa._RSAPublicKey object at 0x7f0dcf7b6eb0>

然后在public_key.verify(signature, message, PKCS1v15(), SHA256())时,验证不过去。以下为拼凑的sign_str,还请帮助看看在哪一步出现了问题,非常感谢!

例如,验签拼凑字符串为: 1627890132 Fnqw2Aw6k1fIxb8DhPAKogL76BeSnvQ6 {"id": "3e283601-7c3d-5c04-8ebf-225474439c26", "create_time": "2021-08-02T15:42:11+08:00", "resource_type": "encrypt-resource", "event_type": "TRANSACTION.SUCCESS", "summary": "支付成功", "resource": {"original_type": "transaction", "algorithm": "AEAD_AES_256_GCM", "ciphertext": "ECIKoyOZBc9soYj7gVqD1JRzXA+0LSPcbm6lPXqIqB/iLTWk9jR6En9z6vVPHpTDKIySzFb4/A9+fViPQJYMCa8tGqwA2HzMCB52PyRTRQ7nrBLBR7lQyHMZbWDqU35tujTmu4KGuO8nplOV4Q7rm+dXFt5RN7XJwbyufTQmU1FviWfzTwe7sT4ndnf4YhY7V0z7m2AhboQXGxdpSYccHLIGFpZctL4VFE1qJ4ikHdNJNvj6RF/yTElP2ssDVHd4lKckuqZ8u7xa5jmhvxzqkJIAFsVDEHKvM4wUkmgV6B6XIeuXMvxi1JNTW33hTnNWTZphcE467Ge/l2ajJckDNKJTeRv50nY+JLm6K2I7f2kmvxHm9OYpCkHlzXWqieMrPrwQs1KbfTqxYaUYW9vOESRXAAOV7q7YfMCkvfjnyX7KQEKYIsKYHPUnpWpJbBRriAH1oY5DC0SoLmlbaCEvwiaEJg7MFwhFVQYLxwk2DsIjbFC1UUxLIs5tZvKUrWFmbQOUTzmnCv/0qU7KbVZbeaHVEFzZ8d1UG1SK/db+medh65ueEwgko9DIvdCITnXTceS3AwTdre2T", "associated_data": "transaction", "nonce": "123RUOfxtcAL"}}

minibear2021 commented 3 years ago

”验证签名失败,但解密返回值正确。“ 验证签名在解密之前,签名失败应该不会走到解密这一步,decrypt_callback的第一步就是_verify_signature,在_verify_signature里才会调用rsa_verify并走到public_key.verify这一步。 建议更新到1.0.5版调试一下并补充点更详细的信息。

carter8225 commented 3 years ago

感谢回复。更新到1.0.5之后问题还是存在。

你说的没错,如果验签错误,是不会到解密的步骤。但因为验签不过,我为了测试支付功能能否正常完成,调整为只显示验签结果,并没有把验签结果作为解密的前置步骤。

我把1.0.5版本首先通过zip方式下载到本地,然后把里面的py文件都添加到我的项目里面(便于调试)。通过设置log可以获取到self._verify_signature(headers, body)返回的是false, 其中headers=request.headers, body=request.body或者json.dumps(json.loads(request.body)或者json.dumps(json.loads(request.body), ensure_ascii=False)),都测试了,返回均为false.

我查看了证书文件,应该是已经从支付平台下载了,并存放到cert目录。生成公钥时,也是通过这个证书生成的。

由于解密使用的是商户平台的apiv3,这个是解密成功的,可以获取到回调函数中request.body的内容。

目前遇到的问题,就是验签过不了...

carter8225 commented 3 years ago

引用插件: requests: 2.26.0 cryptography: 3.4.7

项目部署到centos 7上,uwsgi+nginx

minibear2021 commented 3 years ago

疫情隔离全天溜娃,没时间调试,抱歉。 我刚看了一下官方go语言库的实现,回调验证和响应验证用的是同一个验证器,和我这里实现方式类似,理论上应该是ok的,你尝试将request.text作为body参数的值传入试一下,我怀疑可能是编码的问题。

carter8225 commented 3 years ago

不着急哈,等你有空时帮忙看看。是不是官方的回调返回内容作了调整,比如说加密方法。

request.text没有这个,下面是获取到的错误信息。 'WSGIRequest' object has no attribute 'text'

carter8225 commented 3 years ago

我已经解决问题了。

回调中的验签body应为body = str(request.body, 'utf-8'),这样就可以了。

minibear2021 commented 3 years ago

谢谢反馈,request.body默认是bytes,1.0.6版本已经解决了这个问题,直接或decode后传入皆可,代码做了兼容处理。