You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3中POST请求SHA256签名无效问题求助

排查POST请求SHA256签名无效问题

问题背景

需要向要求SHA256哈希签名认证的服务发送POST请求,已持有app_id和app_secret,按照服务商步骤实现后,GET请求签名验证正常,但POST请求始终返回「无效签名」错误。

服务商要求的签名生成步骤:

  1. 构建MAC字符串,包含以下元素拼接:
    AppId + HTTP Method + URI + UNIX Timestamp + Nonce(请求唯一字符串) + payload的MD5转base64字符串
  2. 使用AppSecret对上述字符串生成SHA256 HMAC哈希
  3. 最终认证签名格式:ApiKey AppId:hash:nonce:timestamp

用户原有代码(POST请求部分):

app_id = 'my_app_id'
app_secret = 'my_app_secret'
providerURL = 'https://the_provider_url'

# POST请求调用代码
def publish_data(number, date, status):
    endPointUrl = providerURL + "/v1/posting"
    
    # 测试用参数
    number = '123456789'
    date = None # 可选参数
    status = 'valid'
    
    payload = "?number={}&date={}&status={}".format(str(number), str(date), str(status))
    strHash = hmac_generator(endPointUrl, 'POST', payload)
    request_headers = {'Authorization': "ApiKey " + strHash, 
                       'Content-Type': 'application/x-www-form-urlencoded'
                       }
    response = requests.post(endPointUrl, headers=request_headers)
    print('RESPONSE:', response.text)

# HMAC生成函数
def hmac_generator(uri, method, body=None):
    timestamp = int(time.time())
    nonce = str(uuid.uuid4())

    content = ""
    if body is not None:
        body_md5 = hashlib.md5(body.encode('utf-8')).digest()
        content = base64.b64encode(body_md5).decode('utf-8')
    
    message = app_id + method + uri + str(timestamp) + nonce + content
    message_bytes = message.encode('utf-8')
    
    # 生成SHA256哈希
    signature = hmac.new(app_secret, msg=message_bytes, digestmod=hashlib.sha256).digest()
    hashed = base64.b64encode(signature).decode('utf-8')

    return "{}:{}:{}:{}".format(app_id, hashed, nonce, timestamp)

问题排查

POST请求签名无效的核心问题集中在payload处理不匹配,具体有以下几点:

  • Payload格式与发送不匹配:用户将POST的payload构造成带?的QueryString格式,但实际发送请求时未传递该payload,导致服务端收到的请求体为空,而签名计算用的是带?的字符串,两边payload的MD5值完全不一致。
  • 可选参数处理错误:当date为None时,str(date)会转换成字符串'None',但服务商可能要求忽略该参数(不加入payload)或用空字符串代替,导致签名计算的payload与服务端预期不符。
  • HMAC密钥编码问题:hmac.new要求密钥为字节串,直接传入字符串app_secret会依赖系统默认编码,可能与服务商的编码方式不一致。

修复后的代码

1. 修正POST请求的Payload处理

将payload改为标准表单键值对格式,实际传递给请求体,同时处理可选参数:

import requests
import time
import uuid
import hashlib
import hmac
import base64

app_id = 'my_app_id'
app_secret = 'my_app_secret'
providerURL = 'https://the_provider_url'

def publish_data(number, date, status):
    endPointUrl = providerURL + "/v1/posting"
    
    # 测试用参数
    number = '123456789'
    date = None # 可选参数
    status = 'valid'
    
    # 构建表单数据,忽略None值的参数
    payload_data = {
        'number': number,
        'status': status
    }
    if date is not None:
        payload_data['date'] = date
    
    # 将表单数据编码为x-www-form-urlencoded格式的字符串(用于签名计算)
    payload = requests.models.URL_ENCODED_FORM_ENCODER.encode(payload_data)
    
    strHash = hmac_generator(endPointUrl, 'POST', payload)
    request_headers = {
        'Authorization': f"ApiKey {strHash}", 
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    # 发送POST请求时传递表单数据
    response = requests.post(endPointUrl, headers=request_headers, data=payload_data)
    print('RESPONSE:', response.text)

2. 修正HMAC生成函数的编码问题

确保密钥是字节串,统一编码逻辑:

def hmac_generator(uri, method, body=None):
    timestamp = int(time.time())
    nonce = str(uuid.uuid4())

    content = ""
    if body is not None:
        # 统一处理body的编码
        if isinstance(body, bytes):
            body_bytes = body
        else:
            body_bytes = body.encode('utf-8')
        body_md5 = hashlib.md5(body_bytes).digest()
        content = base64.b64encode(body_md5).decode('utf-8')
    
    message = app_id + method + uri + str(timestamp) + nonce + content
    message_bytes = message.encode('utf-8')
    
    # 将app_secret转为字节串
    secret_bytes = app_secret.encode('utf-8')
    signature = hmac.new(secret_bytes, msg=message_bytes, digestmod=hashlib.sha256).digest()
    hashed = base64.b64encode(signature).decode('utf-8')

    return f"{app_id}:{hashed}:{nonce}:{timestamp}"

验证要点

  • 确认生成签名用的payload和实际发送给服务端的payload完全一致(包括参数顺序、编码方式)
  • 检查可选参数的处理逻辑是否符合服务商文档要求(比如date为None时是否需要从payload中移除)
  • 确保HMAC生成时所有字符串都使用UTF-8编码,避免因编码差异导致签名不一致

内容的提问来源于stack exchange,提问作者Paulo Matos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 07:27:51