JavaScript与Python生成的HMAC不匹配,疑因引号问题求助
HMAC生成不一致问题排查
JavaScript客户端实现
客户端通过以下代码生成HMAC:
generateHMAC: function (payload) { return new Promise((resolve) => { let hmacpsk = app.get('secret_key'); const hmac = crypto.createHmac('sha256', hmacpsk).update(JSON.stringify(payload)).digest('hex'); resolve(hmac); }) }
对应的payload:
{"patients":[{"id":96,"position":[40.475268,-3.6957545],"area_id":38,"visit":30}],"doctors":[{"id":18,"position":[40.45993,-3.686387],"area_id":38,"start_timestamp":"2022-12-11T23:00:00.000Z","visit":240}],"areas":[{"area_id":38,"transport":"walking"}]}
JSON.stringify(payload)的输出(标准JSON格式,双引号、无额外空格):
"{\"patients\":[{\"id\":96,\"position\":[40.475268,-3.6957545],\"area_id\":38,\"visit\":30}],\"doctors\":[{\"id\":18,\"position\":[40.45993,-3.686387],\"area_id\":38,\"start_timestamp\":\"2022-12-11T23:00:00.000Z\",\"visit\":240}],\"areas\":[{\"area_id\":38,\"transport\":\"walking\"}]}"
生成的哈希值:
84257087ef9cf31f376a8b39e36ac0d97de91d53c8e373cb1e936a51ca5664a2
Python服务端实现
服务端当前代码:
#get the body of the request values = json.loads(request.get_data(as_text=True)) #generate new hmac clave=hmac.new(b"secret_key", bytes(str(values), 'utf-8'), digestmod=hashlib.sha256).hexdigest() print("The new key is:") print (clave)
str(values)的输出(Python字典字符串表示,单引号):
"{'patients':[{'id':96,'position':[40.475268,-3.6957545],'area_id':38,'visit':30}],'doctors':[{'id':18,'position':[40.45993,-3.686387],'area_id':38,'start_timestamp':'2022-12-11T23:00:00.000Z','visit':240}],'areas':[{'area_id':38,'transport':'walking'}]}"
生成的哈希值:
a156bdf7a0c05443337bbf02ebe555b9004d275089c6bc5dae2ebff64d01f170
问题
两端生成的HMAC不一致,怀疑是引号问题但替换后仍未解决,请问问题出在哪里?
问题根源与解决方案
核心问题
Python端使用str(values)序列化对象是错误的:这是Python字典的自定义字符串表示,并非标准JSON格式,和JS的JSON.stringify输出存在多处关键差异:
- 引号类型:Python用单引号,JSON标准要求双引号
- 格式细节:
str(values)可能包含额外空格、不同的键顺序(旧Python版本),甚至特殊字符的处理差异
这些差异会导致HMAC计算的原始字符串完全不同,最终哈希值自然不一致。
解决方案
方案1:直接使用原始请求体字符串(最优)
JS端是对JSON.stringify(payload)的结果生成HMAC,而这个结果就是请求的原始Body内容。因此Python端无需解析JSON,直接用原始请求体字符串计算HMAC:
import hmac import hashlib # 获取原始请求体文本 raw_body = request.get_data(as_text=True) # 直接用原始字符串生成HMAC clave = hmac.new(b"secret_key", raw_body.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() print("The new key is:", clave)
方案2:解析后重新序列化(需严格对齐格式)
如果必须先解析JSON做处理,再生成HMAC,要使用json.dumps()而非str(),并指定参数和JSON.stringify对齐:
import json import hmac import hashlib values = json.loads(request.get_data(as_text=True)) # 生成和JSON.stringify一致的标准JSON字符串 json_str = json.dumps( values, separators=(',', ':'), # 去掉默认空格,和JS紧凑格式一致 ensure_ascii=False, # 非ASCII字符处理和JS对齐 sort_keys=False # 保持键的顺序(Python3.7+默认保留插入顺序) ) clave = hmac.new(b"secret_key", json_str.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() print("The new key is:", clave)
内容的提问来源于stack exchange,提问作者Paloma Jimeno
相关产品推荐
相关产品推荐

