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

Python实现的HMAC-SHA256签名逻辑转PHP后结果不一致如何解决

问题根因与修复方案

1 核心差异:JSON序列化结果不一致

哈希值不匹配最主要原因是Python和PHP的JSON序列化默认规则不同:

  • Python json.dumps() 默认使用的分隔符为 (', ', ': '),也就是逗号、冒号后都会加空格,序列化结果为 {"user_id": "Frank", "query": "Dog"}
  • PHP json_encode() 默认使用的分隔符为 (',', ':'),逗号、冒号后无空格,序列化结果为 {"user_id":"Frank","query":"Dog"}
    输入HMAC算法的原始字符串字节流完全不同,最终得到的签名自然不一致。
    跨语言做签名校验时,永远不要依赖各自语言的默认序列化配置,必须显式统一序列化规则。

2 次要问题:不必要的UTF-8编码转换

PHP的utf8_encode()函数作用是将ISO-8859-1编码的字符串转为UTF-8,如果你当前PHP环境的默认编码已经是UTF-8(绝大多数现代环境默认配置),重复调用该函数会改变原始字符串的字节序列,进一步导致签名计算错误。

修复方案

方案1:对齐Python到PHP的序列化规则(更推荐,无空格JSON传输效率更高)

修改Python的序列化代码,显式指定分隔符和PHP对齐:

message_encoded = json.dumps(message, separators=(',', ':')).encode('utf-8')

PHP端无需调整json_encode,只需去掉多余的utf8_encode调用即可:

<?php
$secret = "cd01985/813hip914Vnn04&1#11ai761";
$message = array(
    'user_id' => "Frank",
    'query' => "Dog"                              
);
$message_encoded = json_encode($message);
$hmac_signature = hash_hmac('sha256', $message_encoded, $secret, false);
// 输出结果和原Python代码一致:ab742454c0158c3ec8d8c9c8965381567d45bee77e6f8d9aacb2239587285f87
?>

方案2:对齐PHP到Python的默认序列化规则

如果不能修改Python代码,PHP端可以手动处理JSON序列化结果,匹配Python的默认分隔符规则:

$message_encoded = json_encode($message);
// 替换冒号和逗号,添加空格匹配Python默认格式
$message_encoded = str_replace([':', ','], [': ', ', '], $message_encoded);

注意该方案只适用于JSON值不含冒号、逗号的简单场景,复杂场景建议统一显式指定序列化参数。

补充问题解答

Python json.dumps() 没有直接对应的PHP原生默认实现,因为两种语言的默认序列化配置存在多处差异,除了分隔符之外,还包括中文转义、斜杠转义、空数组/对象处理等规则。如果要完全对齐,需要两边同时显式指定所有序列化参数:

  • Python侧显式配置ensure_ascii、separators、sort_keys等参数
  • PHP侧显式配置JSON_UNESCAPED_UNICODE、JSON_UNESCAPED_SLASHES、JSON_FORCE_OBJECT等参数
    额外建议:对JSON的键按固定顺序排序后再序列化,可以避免因为键顺序不同导致的序列化结果差异。

内容的提问来源于stack exchange,提问作者Fredrik Carenborn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:33:01