Python与JS中HMAC输出不一致问题求助(不可修改Python代码)
问题原因及解决方案
核心差异点
- 哈希数据的处理逻辑:
- Python中
hashlib.sha256(...).digest()返回二进制字节(bytes),直接拼接到字符串时,Python会自动将其转为b'\xXX\xXX...'格式的字符串表示,再通过encode('utf-8')转成字节流参与HMAC计算。 - 你的JS代码直接将
CryptoJS.SHA256的结果(WordArray)转为十六进制字符串,和Python的处理逻辑完全不匹配。
- Python中
- JSON序列化一致性:
- 虽然Python的
json.dumps和JS的JSON.stringify默认行为接近,但要确保对象键顺序、空格处理完全一致(两者默认都不排序键,只要数据结构一致即可)。
- 虽然Python的
修正后的JS代码
情况1:严格匹配Python原代码的字符串拼接逻辑
如果Python代码确实是将bytes对象转为字符串表示后拼接,使用以下代码:
var CryptoJS = require("crypto-js"); const date = "2024-01-16 16:11:11"; const nonce = 'ksjdnf5646512'; const data = {key: 'value'}; // 替换为实际业务的value值 const method = 'PATCH'; const api = 'api'; const content_type = 'application/json'; // 1. 生成和Python json.dumps一致的JSON字符串 const dataStr = JSON.stringify(data); // 2. 计算SHA256并转为Python风格的bytes字符串表示 const sha256Result = CryptoJS.SHA256(dataStr); const bytes = []; for (let i = 0; i < sha256Result.sigBytes; i++) { const byte = (sha256Result.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; bytes.push(byte); } const hashedDataStr = `b'${bytes.map(b => `\\x${b.toString(16).padStart(2, '0')}`).join('')}'`; // 3. 构建待哈希的完整字符串 const stringToHash = `${method}\n${date}\n${api}\n${content_type}\n${nonce}\n${hashedDataStr}`; // 4. 计算HMAC-SHA256并转为十六进制字符串 const hmacString = CryptoJS.HmacSHA256(stringToHash, 'secretkey').toString(CryptoJS.enc.Hex); console.log(hmacString);
情况2:修正为常规HMAC签名逻辑(更合理)
如果Python代码是笔误,实际应该拼接各部分的字节流(这是接口签名的常规做法),使用以下代码:
var CryptoJS = require("crypto-js"); const date = "2024-01-16 16:11:11"; const nonce = 'ksjdnf5646512'; const data = {key: 'value'}; // 替换为实际业务的value值 const method = 'PATCH'; const api = 'api'; const content_type = 'application/json'; // 1. 生成一致的JSON字符串并计算SHA256二进制哈希 const dataStr = JSON.stringify(data); const hashedData = CryptoJS.SHA256(dataStr); // 2. 拼接所有部分的字节流(包含换行符) const parts = [ CryptoJS.enc.Utf8.parse(method), CryptoJS.enc.Utf8.parse('\n'), CryptoJS.enc.Utf8.parse(date), CryptoJS.enc.Utf8.parse('\n'), CryptoJS.enc.Utf8.parse(api), CryptoJS.enc.Utf8.parse('\n'), CryptoJS.enc.Utf8.parse(content_type), CryptoJS.enc.Utf8.parse('\n'), CryptoJS.enc.Utf8.parse(nonce), CryptoJS.enc.Utf8.parse('\n'), hashedData ]; const stringToHash = parts.reduce((acc, part) => acc.concat(part), CryptoJS.lib.WordArray.create()); // 3. 计算HMAC-SHA256并转为十六进制字符串 const hmacString = CryptoJS.HmacSHA256(stringToHash, CryptoJS.enc.Utf8.parse('secretkey')).toString(CryptoJS.enc.Hex); console.log(hmacString);
验证方法
运行Python代码时,打印出string_to_hash和hashed_data的值,对比JS代码中生成的对应内容,确保两者完全一致后,再验证最终的HMAC结果是否匹配。
内容的提问来源于stack exchange,提问作者Deepak Babu
相关产品推荐
相关产品推荐

