1. API签名认证
API签名认证是一种用于保护Web API的身份验证机制。它用于验证发送API请求的客户端或用户的身份,并确保请求数据在传输过程中没有被篡改。API签名认证通常涉及以下步骤:
- 请求创建: 客户端创建API请求,并包括必要的请求参数、数据和请求头
- 签名生成: 客户端使用密钥和一些请求信息(如时间戳等)来生成一个唯一的数字签名sign。签名生成通常使用哈希算法(如HMAC-SHA256)
- 签名附加: 客户端将生成的数字签名附加到API请求中,通常是在请求头或请求参数中
- 服务器验证: 服务端收到API请求后,会使用相同的密钥和接收到的请求信息来生成签名。然后,它将生成的签名与请求中的签名sign进行比较。
⚠️如果生成签名的过程中没有使用某个请求数据,那么对该请求数据的篡改将是不可知的
在日常使用软件中,我们可能会注意到有两种API认证方式:
-
方式一:只有一个密钥
在注册SM.MS图床后,网站会提供一个Secret Token(可以随时查看),把Secret Token填写到PicGo这类软件中后,就可以方便地将图片上传到SM.MS
-
方式二:有两个密钥
在注册腾讯云后,网站会提供给我们一对密钥,分别叫SecretId和SecretKey,且SecretKey只能在创建时告诉用户一次,之后无法查看,只能重新创建。有了这两个密钥,我们就可以通过ddns-go动态修改所购买域名的域名解析。
这两种认证方式是如何工作的?有什么区别?
1.1 单密钥
网站给你一个 SecretToken,你在软件中配置这个 Token,它会被加到 HTTP 请求头中:
POST /upload
Authorization: Bearer sk_123456789abcdef
在这种场景下,SecretToken就是用户的身份标识。但是和JWT还不同,SecretToken中并不包含状态信息(Payload),它只是一个静态的、用户唯一的标识。当网站接受到你的请求时,他会在自己的数据库中查询有没有这个Token并确定你是谁。
单密钥的整个过程不涉及加密/签名,轻量简单。
1.2 SecretId+SecretKey
在这种场景下,SecretId 相当于你的用户名,SecretKey 则是你的密码,用于签名(不直接参与网络传输)。每次请求都要用这两个参数进行签名计算,类似这样:
POST /ddns/update
Action: UpdateDomainRecord
Timestamp: 1682341234
SecretId: sid_123456789
Signature: sha256_hmac(secretKey, 所有参数)
{
"domain": "a.com",
"ip": "1.2.3.4"
}
当服务端接收到这个请求时,首先根据SecretId去数据库中查询对应的SecretKey,然后对请求参数(Timestamp、SecretId、domain,ip)进行同样的签名操作,然后与Signature进行比较。总的来说,SecretId+SecretKey的方案依然是一种对称加密(哈希消息认证码,HMAC)。
防篡改
签名计算的目的是为了防止请求参数的篡改。例如,你的请求被某个中间人截获,如果他修改某个请求参数(他无法修改Signature),那么服务端进行签名操作得到的结果就会和Signature不同,进而拒绝请求。
防重放
-
Timestamp
携带Timestamp是为了防止重放攻击。想象某个中间人截获了你的转账请求,他不进行数据篡改,而是反复重放该请求,那么也会造成攻击效果。为此可以将请求的时间戳作为参数的一部分,也进行签名(这意味着攻击者无法篡改时间戳),后端在执行业务逻辑之前首先判断该时间戳是否在范围之内。
-
nonce(随机串)+缓存机制
单纯携带Timestamp并不能解决“短时重放攻击”的问题,为此,可以再加上一招:nonce(随机串)+缓存机制。客户端请求时,加入
timestamp + nonce参数,服务端校验时,判断timestamp在时间窗口内(如1分钟),且在该时间窗口内 nonce 是否首次出现。如果nonce在时间窗口内已经出现过一次,直接拒绝请求,否则将nonce加入缓存(如 Redis),设置过期时间 1分钟接收到请求 ↓ 检查 timestamp 是否过期 ↓ 检查 nonce 是否在缓存中 ├─ 是 → 拒绝(重放) └─ 否 → 验证签名 → 缓存 nonce(5分钟) → 通过
1.3 非对称加密
上面提到了SecretId+SecretKey的方案本质是一种对称加密,那么为什么需要非对称加密,以及它是如何工作的?
分析SecretId+SecretKey的工作流程,客户端需要使用SecretKey对请求数据进行签名,尽管普通的业务不会发生SecretKey的传输,但用户获取自己SecretKey的过程依然会发生SecretKey的传输(这也是为什么腾讯云只给你看一次SecretKey,再想查看只能重建)
以HTTPS来说明非对称加密的流程:
- 服务器把公钥发给客户端
- 客户端生成一个对称加密用的 AES 密钥
- 客户端用服务器公钥加密 AES 密钥,发回给服务器
- 服务器用私钥解密得到 AES 密钥
- 后续通信用 AES(对称加密)进行加密传输
非对称加密的目的是为了传输一个对称加密通信使用的密钥AES(相当于上面的SecretKey,但避免了直接传输),一旦完成了AES的传输,后续的通信是通过对称加密实现的。用公钥加密的数据只有对应的私钥才能解密,客户端从始至终都不知道私钥,也从未发生AES密钥的直接传输。