从原理到实战,彻底搞懂 API 签名如何保护你的接口,以及它与 JWT 的本质区别
API 签名(API Signature)是一种基于密钥的请求认证与完整性校验机制。客户端在发送请求前,使用预共享密钥(Secret Key)对请求的关键参数进行加密运算,生成一串不可逆的签名值,随请求一起发送;服务端收到后用同样的密钥和算法重新计算签名,比对两者是否一致来验证请求的合法性。
签名本身不加密数据内容,而是为数据生成一个"数字指纹"。任何对数据的篡改都会导致指纹不匹配,从而被服务端拒绝。
POST /api/device/data
timestamp=1700000000
device_id=sensor_01
temperature=23.5
POST /api/device/data
timestamp=1700000000
device_id=sensor_01
temperature=23.5
sign=a3f8c2...e7d1
HTTP 协议本身是明文传输,没有任何身份校验和完整性保护。如果不加签名,API 将面临以下威胁:
攻击者截获请求后修改参数(如把转账金额从 100 改为 10000),服务端无法识别数据已被篡改
攻击者截获合法请求后原样重发,如重复提交订单、重复执行设备控制指令
任何人只要知道 API 地址就能调用,无法确认请求者的真实身份
如果直接在请求中传递密钥,一旦被抓包密钥即泄露。签名机制中密钥不参与传输
签名由请求参数 + 密钥共同计算,改任何参数签名都会变
加入 timestamp + nonce,服务端校验时间窗口和唯一性
AccessKey 标识身份,SecretKey 参与签名,密钥不传输
HMAC 单向运算,密钥永远不出现在网络传输中
以最常见的 HMAC-SHA256 签名方案为例,完整流程如下:
将请求方法、路径、时间戳、关键参数按固定规则拼接成待签名字符串
HTTP方法\n路径\n时间戳\n参数排序拼接
使用预共享的 Secret Key 作为密钥,对签名串做 HMAC-SHA256 运算,得到二进制摘要
hmac_sha256(secret_key, string_to_sign)
将二进制摘要编码为可传输的字符串形式,作为 sign 参数
sign = base64(hmac_digest)
将 access_key、timestamp、sign、nonce 放入请求头或查询参数
X-Access-Key / X-Timestamp / X-Sign / X-Nonce
服务端用 access_key 查出对应的 secret_key,用同样算法重算签名,比对是否一致;同时校验 timestamp 时间窗口和 nonce 唯一性
不同云厂商规则不同,但核心思路一致——把所有影响请求语义的字段纳入签名,确保任何篡改都能被检测到:
服务端校验请求时间与当前时间的差值(如 ±5 分钟),过期请求直接拒绝
每次请求携带唯一随机串,服务端缓存近期 nonce 拒绝重复值
timestamp 和 nonce 参与签名计算,攻击者无法替换它们而不破坏签名
两者都能做身份认证,但设计哲学和适用场景截然不同。理解差异的关键在于:签名是"请求级"验证,JWT 是"会话级"凭证。
每次请求都要重新计算签名,签名值随请求内容变化。验证的是"这个请求是否被篡改"。
登录时颁发 Token,后续请求携带即可,Token 内容固定。验证的是"你是谁、你有什么权限"。
| 维度 | API 签名 (HMAC) | JWT |
|---|---|---|
| 核心用途 | 请求完整性 + 身份认证 | 身份声明 + 权限传递 |
| 密钥持有 | 双方持有对称密钥 | 签发方私钥 / 验证方公钥 |
| 每次请求计算 | 是,必须重算 | 否,Token 固定 |
| 防篡改 | 强,参数级绑定 | 仅 Token 本身防篡改 |
| 防重放 | 内置(timestamp+nonce) | 需额外机制(exp/jti) |
| 是否自包含 | 否,服务端需查密钥 | 是,Payload 自带声明 |
| 状态管理 | 无状态(但 nonce 需存储) | 有状态(吊销需黑名单) |
| 计算开销 | HMAC 很轻 | RSA/ECDSA 较重 |
| 适用客户端 | 设备 / 服务端(可保密密钥) | 浏览器 / App(不能保密密钥) |
| 密钥轮换 | 需同步更新双方 | 仅签发方更新 |
| 典型场景 | AWS API、阿里云、IoT 设备上报 | 用户登录、SSO、微服务间鉴权 |
API 签名是"对每个请求做不可伪造的指纹",JWT 是"一张可以反复出示的身份证"。前者保护请求不被篡改和重放,后者证明持有者的身份和权限。两者可以组合使用:JWT 管用户身份,签名管请求完整性。
物联网场景有其独特约束:设备资源受限、网络不稳定、设备数量巨大、安全要求高。选型时需要特别考虑这些因素。
为每台设备分配 AccessKey + SecretKey,每次请求签名验证。
设备登录获取 Token,后续请求携带 Token。
| 平台 | HTTP API | MQTT 连接 | 签名算法 |
|---|---|---|---|
| AWS IoT Core | SigV4 签名 | 签名 + TLS 双向认证 | HMAC-SHA256 |
| 阿里云 IoT | 签名机制 | 签名 + MQTT Password | HMAC-SHA256 / SM3 |
| 腾讯云物联网 | 签名机制 | 签名 + MQTT Password | HMAC-SHA256 / SHA1 |
| Azure IoT Hub | SAS Token (类签名) | SAS Token + X.509 | HMAC-SHA256 |
| EMQX | JWT / 签名可选 | JWT / 签名可选 | 灵活配置 |
HTTP/CoAP 数据上报 → HMAC 签名(每个请求独立验证,防篡改防重放)
MQTT 长连接 → 签名 + TLS 双向认证(连接时签名鉴权,运行中 TLS 保护)
JWT 仅作辅助,适用于需要跨服务传递身份声明的场景,不作为设备主认证手段。
在下方模拟一次完整的 API 签名流程,理解每个步骤的实际输出:
用上面的参数生成签名后,尝试修改下方参数看签名是否还能匹配: