为什么要做 API 签名
签名通过以下方式帮助保护请求:
- 验证请求者的身份:签名确保请求是由持有有效访问密钥的人发送的
- 保护传输中的数据:为了防止请求在传输过程中被篡改,API 提供方会使用请求参数来计算请求的哈希值,并将生成的哈希值加密后作为请求的一部分,发送到 API 提供方。服务器会使用收到的请求参数以同样的过程计算哈希值,并验证请求中的哈希值。如果请求被篡改,将导致哈希值不一致,API 提供方将拒绝本次请求。
如何进行 API 签名
申请安全凭证
本文使用的安全凭证为密钥,密钥包括 AccessKey 和 SecretKey。每个用户最多可以拥有两对密钥。
AccessKey:用于标识 API 调用者身份,可以简单类比为用户名SecretKey:用于验证 API 调用者的身份,可以简单类比为密码- 用户必须严格保管安全凭证,避免泄露,否则将危及财产安全。如已泄漏,请立刻禁用该安全凭证。
以上安全凭证的颁发,是由 API 接口提供方进行颁发,具体如何设计网上大把文章,可自行搜索参考。
签名过程
假设 API 提供商颁发给用户的凭证如下:
AccessKey: a416230515674b29a7ca05b0e3f135c4SecretKey: 74b65fd87b354a8ea873332b53a0cf0e
1. 拼接待签名字符串
按如下伪代码格式拼接规范请求串:
1 | StringToSign = HTTPMethod + Timestamp + SignatureNonce |
| 字段名称 | 解释 | 示例值 |
|---|---|---|
| HTTPMethod | HTTP 请求方法(GET、POST)。本示例取值为 POST |
POST |
| Timestamp | 时间戳。本示例采用 RFC3339 标准时间戳 |
2022-07-11T19:14:41Z |
| SignatureNonce | 签名字符串,随机值,用于防止网络重放攻击。在不同请求间要使用不同的随机数值 | 52a82619176942e597a6c946963ffd0c |
2. 计算签名
我们此处使用
HMAC-SHA1签名认证算法来实现本次签名示例,也可使用其他算法,主要是需要考虑跨语言是否有标准库实现了该算法。
本文我们以 go 语言来实现签名,具体的伪代码如下:
1 | // Sign API接口签名 |
上述方法中,外部构建好 http.Request 后,只需要将 http.Request 传入到该方法中,即可完成签名字符串的获取。
最终在签名完成后,得到的 http Query 应该是这样的:
1 | AccessKeyId=a416230515674b29a7ca05b0e3f135c4&Signature=GgLvBm1EaaOI4kZ9i6s4BBoY0W4%3D&Timestamp=2022-07-11T19%3A14%3A41Z&SignatureNonce=fanerblog |
3. API 提供方验证签名
道理其实一致,只需要按照相同方法进行签名,最后比对签名是否一致,若一致则表示该请求确实来自颁发凭证的调用方发起。因为 SecretKey 是仅有颁发者和被颁发者拥有的,若 SecretKey 不一致,产生的签名也无法校验通过。此处就不进行过多的演示了。
结语
以上仅是对 API 签名的简单演示与原理讲解,目前主流的签名算法在网上比较多,大家可自行参考,以确保自己提供给到第三方的接口安全性问题,若是计费型接口,被他人盗用,造成的损失是无法估量的。