介绍
API 签名认证算法是一种用于保证 API 请求的安全性和完整性的一种机制,通过在 API 请求中添加签名字段来验证请求发送者的身份,并确保请求在传输过程中没有被篡改。
作用
- 身份验证:验证请求发送者的身份是否合法
- 防止篡改:防止请求参数在传输过程中被篡改
- 防止重放攻击
重放攻击是一种网络安全攻击方式,攻击者会在网络通信过程中,通过截获合法的通信数据包,然后将这些数据包重新发送到目标系统,以欺骗系统进行非法操作或者获取敏感数据。
实现思路
密钥
每个用户都分配有一对密钥 accessKey / secretKey(ak / sk),accessKey 是用户的标识,secretKey 是用于生成签名的密钥。
生成签名
用 请求参数 拼接 sk 密钥 后,再用 加密算法(如 md5)加密,即得到签名(sign)。
请求参数 + sk 密钥 => 加密算法 => 签名
校验签名(身份验证)
用户生成签名后,将 ak 和 签名 放在请求中一起发送(可放在请求头中)。
服务端接收到请求后,从请求中拿到 请求参数、ak、签名。
根据 ak 去查询用户得到其 sk,用 请求参数、sk 生成签名,用此签名和请求中的签名比较是否相等;若相等,则签名校验通过,请求发送者身份合法;若不相等,则校验失败,身份不合法。
防止篡改
签名是用 请求参数 拼接 sk 密钥 后生成的,请求参数不同,生成的签名也就不同。
如果在请求传输过程中,请求参数被篡改,那么服务端拿到被篡改的请求参数后,用其生成的签名与用户发送的签名就会不同(用于生成签名的请求参数不同),则签名校验失败,失败原因是请求参数被篡改。
因此,如果签名校验通过,则说明请求参数没有被篡改。
防止重放攻击
每次请求生成一个随机数 nonce(随机数基本不会重复),放入到请求中;服务端会保存每次请求的随机数(可以用 redis 保存)。
具体的校验逻辑是:
判断随机数是否已被保存在服务端。
如果是,则说明请求是重放的,拒绝请求。原因是,如果请求是合法请求重放的,对应的合法请求被服务端接收时,随机数就会被保存;请求被重放,随机数自然判断已存在。
如果不是,则说明是正常请求,保存其随机数。
请求中加个随机数可以防止重放攻击,但是所有请求的随机数都要被保存,必定会占用很多的资源;可以在请求中时间戳 timestamp,这样就可以只保存有效时间范围内的请求的随机数,而不用保存全部。
校验逻辑变为:
先判断时间戳是否在有效时间范围内(如 距当前时间 5 分钟范围内):
如果不是,则拒绝请求;
如果是,则继续后面的逻辑判断。
再判断随机数是否已被保存在服务端:
如果是,则说明请求是重放的,拒绝请求;
如果不是,则说明是正常请求,保存其随机数。
当请求的时间戳不在有效时间范围内后,就可以把对应的时间戳从存储中移除,从而减小存储压力。原因是,时间戳过期后,时间戳判断逻辑那里请求就会被拒绝,下一步随机数判断是走不到的,因此随机数“失去作用”,可以移除。
建议使用 redis 保存随机数,可以将过期时间设置为时间戳的有效时间,这样时间戳过期后,随机数也会自动移除。
完整逻辑
用户发送请求时,需带上以下 4 个字段(可放在请求头中):
- accessKey 用户标识
- sign 签名(如何生成见上文)
- nonce 随机数
- timestamp 时间戳
服务端校验逻辑:
- 先从请求中取得各个字段
- 根据 accessKey 查询用户得到 secretKey
- 服务端生成签名
- 校验签名是否一致
- 校验时间戳是否过期
- 校验随机数是否存在
如果有帮助的话,可以点个赞支持一下嘛
🙏