支付平台后台显示回调已送达,Magento 却每次记录 signature mismatch。最关键的证据不是解析后的数组,而是应用收到的原始字节。

一次失败回调要保留什么

  • 请求 ID、到达时间和来源 IP;
  • 签名头名称与算法版本;
  • 原始 body 的 SHA-256,仅在安全环境短期保留脱敏样本;
  • 用于签名的时间戳;
  • 代理是否解压、改写或转换编码。

不要在日志中输出密钥、完整银行卡数据或未经脱敏的请求体。

常见错误是先 json_decode(),业务处理后再 json_encode() 去算 HMAC。键顺序、斜杠、空白和 Unicode 转义任何一个变化,摘要都不同。签名必须用框架读取到的原始 body 按支付平台规定拼接。

$expected = hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
if (!hash_equals($expected, $received)) {
    throw new LocalizedException(__('Invalid signature.'));
}

示例中的拼接格式只是结构说明,实际必须严格使用该支付平台当前协议。

验证通过也不能直接处理两次

校验时间戳允许窗口,保存 event ID 并做唯一约束。平台重试同一事件时应返回成功但不重复开票、发货或改状态。密钥轮换期间可同时验证新旧密钥,但必须记录命中哪一把,并在窗口结束后移除旧密钥。

最终用官方测试事件验证:正常签名成功、改一个字节失败、过期时间戳失败、同一 event 重放不产生第二次业务动作。