Python处理Webhook时使用公钥HMAC签名验证失败问题求解
Webhook签名校验失败修复方案
以下是你代码存在的核心问题及修复方案:
- 算法选型错误:
HMAC-SHA256是对称签名算法,仅适用于共享密钥场景。你提供的是RSA公钥,说明平台采用非对称签名方案,应使用SHA256WithRSA验签,而非HMAC算法。 - 载荷构造错误:你将
event_body解析为字典后再通过json.dumps()序列化,Python默认序列化规则(空格、转义处理)和平台签名时使用的原始请求体字符串不一致,直接导致载荷错误。请直接使用Webhook推送的原始请求体字符串,不要做解析再序列化操作。 - 多余换行符问题:多数平台的待签名串末尾不需要额外添加
\n,你当前构造payload_to_sign时末尾添加的换行符不符合通用规则。 - 公钥处理错误:你将RSA公钥解码为DER格式后直接传入HMAC作为密钥,不符合RSA验签的公钥加载逻辑。
修复后示例代码
首先安装依赖库:pip install cryptography
代码实现:
import base64 from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.exceptions import InvalidSignature # 直接使用完整PEM格式公钥,无需手动截取内容 Publickey = '''-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVAMXVTMIuttHcP1kvSk9V39S7 BqDbY+LC9JfwMzyoubo3fdsqBf4EmB1PfBUigcOL5YBqMKGEE6xmVw6SXCTH4JwX dqJ4IRiXf76YMt6PB0dMzu/qCmhaGFGkqT6vJM0hHyEbtS/P3FR9ZU+eaOvynLWb FvXTzIoctZM1IvDrCwIDAQAB -----END PUBLIC KEY-----''' # 加载RSA公钥 public_key = serialization.load_pem_public_key( Publickey.encode('utf-8') ) WebhookSignature = "VtniwOFAi4oBKFnvHhY6UZ+wPARf7+yWVbE61Hc7JVdRgqKJ40Yk9k5Gb2Y0S0VLUYOOOhUNUsD7R8GDEr6WH84sAEf8bXa1xYMiyjgeGleTg1MxRJCtrHcxMeMCEXPWmKTeLhn6O+cdvDGq4ZpcTTiQnEvk5xHPcxFrBT637zg=" WebhookTimestamp = 1611232922428 WebhookNonce = "5RhaTrZPhknNv0kDSA2UQ67cPMVNS4sA" # 直接使用Webhook推送的原始请求体字符串,不要解析再序列化 raw_event_body = '{"bizType":"PAY","data":"{\\"merchantTradeNo\\":\\"9825382937292\\",\\"totalFee\\":0.88000000,\\"transactTime\\":1619508939664,\\"currency\\":\\"EUR\\",\\"commission\\":0,\\"openUserId\\":\\"1211HS10K81f4273ac031\\",\\"productType\\":\\"Food\\",\\"productName\\":\\"Ice Cream\\",\\"tradeType\\":\\"WEB\\",\\"transactionId\\":\\"M_R_282737362839373\\"}","bizId":29383937493038367292,"bizStatus":"PAY_SUCCESS"}' # 按规则拼接待签名串,可根据平台文档确认是否需要末尾加换行 payload_to_sign = f"{WebhookTimestamp}\n{WebhookNonce}\n{raw_event_body}" # 解码收到的签名 decode_signature = base64.b64decode(WebhookSignature) try: # 执行RSA-SHA256验签 public_key.verify( decode_signature, payload_to_sign.encode('utf-8'), padding.PKCS1v15(), hashes.SHA256() ) print("签名校验通过") except InvalidSignature: print("签名校验失败")
内容的提问来源于stack exchange,提问作者Pun
相关产品推荐
相关产品推荐

