HMAC 签名编码的坑:Go 和 PHP 的不同处理方式

进制 编码 Base64 16 HMAC
发布于 2026-06-12
111

我们非常重视原创文章,为尊重知识产权并避免潜在的版权问题,我们在此提供文章的摘要供您初步了解。如果您想要查阅更为详尽的内容,访问作者的公众号页面获取完整文章。

扫码阅读
手机扫码阅读

文章主旨: 跨语言 HMAC 签名在 Base64 编码前,是否先转换为十六进制字符串将导致结果不同,必须统一编码前的数据格式(直接使用二进制)才能保证一致性。

关键要点:

  • Go 和 PHP 计算 HMAC 时,默认返回的原始二进制数据或十六进制字符串会影响后续 Base64 编码结果。
  • PHP 中 hash_hmac 的第四个参数 binary 决定输出是原始二进制(true)还是十六进制字符串(false,默认)。
  • 直接对 HMAC 二进制结果进行 Base64 编码,输出长度固定且数据可还原;先转十六进制再 Base64 会使数据翻倍,结果完全不同。
  • 跨语言一致性建议:统一使用二进制数据进行 Base64 编码(PHP 中设置 binary=true,Go 中直接使用 base64.StdEncoding.EncodeToString(signatureBytes))。

内容结构:

  1. 问题引入:HMAC 签名在不同语言中因编码方式不同导致签名结果不同,作者因直接将 PHP 签名算法用 ChatGPT 生成未测试而踩坑。
  2. 代码示例:展示 Go 和 PHP 两种编码方式(直接 Base64 与先转十六进制再 Base64)的输出差异。
  3. 原因分析:根本原因是 Base64 编码前的输入数据不同——PHP 的 hash_hmac 默认返回十六进制字符串,而 Go 的 h.Sum(nil) 返回原始二进制;解释了原始二进制与十六进制字符串的区别。
  4. Base64 编码作用:将二进制转为文本便于传输,不改变数据内容,但输入不同导致输出不同。
  5. 保证一致性建议:统一使用二进制数据作为 Base64 编码的输入(PHP 中设 binary=true,Go 中直接对二进制编码)。
  6. 结论:直接对 HMAC 结果进行 Base64 编码可保持数据可还原;先转十六进制再编码会导致数据翻倍且结果不同;跨语言时务必统一编码方式。

文章总结: 本文以实例揭示了 HMAC 签名跨语言编码差异的根本原因,并给出了简单可行的统一解决方案,避免开发中签名验证失败。

鲁飞

鲁飞(沈唁)的个人公众号,不定时分享和PHP相关的技术资源、开源项目、技术总结等内容。

41 篇文章
浏览 67.8K

还在用多套工具管项目?

一个平台搞定产品、项目、质量与效能,告别整合之苦,实现全流程闭环。

加入社区微信群
与行业大咖零距离交流学习
PMO实践白皮书
白皮书上线