轻易云
注册体验

API 签名机制详解:MD5/HMAC 签名原理与八个常见踩坑

· 系统管理员· 工程最佳实践· 16 次浏览· 约 2 分钟读完
API 签名旺店通聚水潭Webhook数据集成

签名到底在防什么

签名机制用一把只有双方知道的密钥(app secret),让接收方能同时确认两件事:请求确实来自持有密钥的合法应用,以及请求参数在传输中没有被篡改。它不提供加密,也不解决身份授权——那是 token 的职责。

典型签名流程(以主流电商 ERP 为例)

不同平台细节略有差异,但骨架一致:

  1. 收集所有业务参数 + 公共参数(app_key、timestamp 等),不包含签名参数本身;
  2. 按参数名的字典序(ASCII)排序;
  3. key1value1key2value2…k1=v1&k2=v2… 形式拼接成字符串;
  4. 在首尾或指定位置拼接 app secret;
  5. 对拼接串做 MD5 或 HMAC-SHA256 计算,MD5 结果通常取大写十六进制;
  6. 把签名放入 sign 参数,随请求一起发送。
ts
// 通用签名函数骨架(具体拼接规则以各平台文档为准)
import crypto from "node:crypto";

function sign(params: Record<string, string>, secret: string): string {
  const sorted = Object.keys(params)
    .filter((k) => k !== "sign" && params[k] !== "")
    .sort()
    .map((k) => k + params[k])
    .join("");
  return crypto.createHash("md5").update(secret + sorted + secret, "utf8").digest("hex").toUpperCase();
}

八个最常见的踩坑

  1. 排序键搞错:按参数名排,不是按值排;字典序是 ASCII 序,不是拼音或本地化排序;
  2. URL 编码时机:有的平台要求拼接前编码、有的要求原值拼接、发送时再编码,规则以文档为准,两套混用必挂;
  3. 中文与特殊字符:MD5/HMAC 输入必须先转 UTF-8 字节,Node 里 update(str, "utf8") 不能漏;
  4. 空值参数:有的平台要求空值参数不参与签名,有的要求参与,差一个参数结果就不同;
  5. 大小写:MD5 结果多数平台要大写,HMAC 十六进制通常小写,弄反直接验签失败;
  6. 数组/嵌套参数:序列化规则(逗号拼接?JSON?)各平台不同,务必实测;
  7. 时间戳不同步:服务器时间偏差超过平台容忍窗口(常见 ±5~15 分钟)会被判重放,生产机务必开 NTP;
  8. secret 泄露进日志:排查问题时打印完整签名串是常见操作,记得脱敏。

排障方法论

签名错误基本是确定性问题,没有玄学:把平台示例请求在本地完整复现,逐字符 diff 你的拼接串与平台串,差异一定藏在排序、编码、空白这三处之一。用平台提供的在线签名工具(if any)交叉验证效率最高。

轻易云连接器已封装各主流平台的签名实现,接入方只需配置 app_key / app_secret,无需关心拼接细节;自研对接时建议把签名逻辑写成纯函数并配平台官方案例做单元测试。

本文为原创内容,转载请注明出处:/insights/engineering/api-signature-mechanism

评论