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

Node.js转PHP实现Webhook HMAC-SHA256签名校验结果不一致问题排查

签名计算不匹配的核心问题

你的实现和原始Node逻辑一共存在3处关键偏差,逐一修正后就能生成和预期完全一致的签名:

  • 密钥处理步骤完全遗漏
    原始Node逻辑中,参与HMAC计算的密钥并不是明文的secretKey,而是先对该值做base64解码得到的二进制内容:Buffer.from(secretKey, 'base64').toString('utf8')。你当前PHP代码直接把原始密钥字符串传入计算,密钥和Node侧不一致,结果从根源上就存在偏差。
  • HMAC输出格式不符合要求
    PHP的hash_hmac函数默认返回十六进制编码的计算结果,而Node.js侧的HMAC是输出原始二进制流后再做base64编码。你当前把十六进制字符串直接做base64编码,相当于多套了一层格式转换,计算结果不可能和预期匹配。必须给hash_hmac传入第四个参数true,强制返回原始二进制数据供后续base64编码。
  • 消息体存在语法错误、序列化逻辑不匹配
    你写的$message = '{'key1':'world','key2':'world'}'本身PHP语法就不合法:单引号包裹的字符串内部直接嵌套单引号没有转义。同时,签名计算使用的消息必须和Node侧拿到的原始请求体字符串完全一致(包括所有空格、引号格式、字节顺序),不能手动拼接结构相似但字符有差异的字符串——哪怕JSON结构完全相同,只要有一个字节差异,签名就会校验失败。

修正后的可运行代码

$timestamp = "1570350275357";
$signatureHeader = "+DCfT1wIMUiaZnlZB4u59/d5wkXKA89lv67Ov66vnyc=";
$secretKey = "mysecretsecret";

// 对齐Node逻辑,对密钥做base64解码
$decodedKey = base64_decode($secretKey);
// 测试环境下用和预期值对应的消息字符串做验证
$message = '{"key1":"world","key2":"world"}';

// 让hash_hmac返回原始二进制,再做base64编码
$signature = base64_encode(hash_hmac('sha256', $timestamp . '.' . $message, $decodedKey, true));

// 验证签名匹配性
var_dump($signature === $signatureHeader); // 输出 bool(true)

实际Webhook校验场景注意:$message不能手动拼接,必须通过file_get_contents('php://input')直接读取PHP接收到的原始请求体内容,禁止对请求体做json_decode再json_encode的二次序列化——否则一旦对方请求体存在自定义空格、字段顺序差异,就会出现签名不匹配的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 11:24:08