使用场景 :
当系统需要与云平台进行对接时,常常会使用api鉴权对权限进行鉴定,我们使用的api鉴权方式即为aksk鉴权,简单而言就是通过签名验证是否具有权限。
假设 :
AKSK鉴权并非该帖子的主题,先略过,假设目前组件与云平台都存在一个对称加密的密匙,且组件内提供了一些API给云平台进行调用。
为什么需要防重放 :
当云平台需要调用组件的api时,需要API鉴权。鉴权方案大概为 :
云平台 :
1) 云平台生成一个随机数,将随机数与api参数一起进行哈希然后利用秘钥进行加密(类似于签名)生成一个code,然后将随机数,api参数和code发送给客户端。
2) 经过SSL加密到达服务端
组件 :
1) 从SSL取得解密的数据
2) 将随机数与api参数一起进行哈希然后利用秘钥进行加密(类似于签名)生成另一个code与收到的code进行比对。
问题 : 虽然上述方案看起来很严谨,又是哈希又是加密还有SSL保护,但仍然存在漏洞。
例如 : 攻击方不一定需要知道你的秘钥是什么,他只需要将你的包再次发送给客户端,他就可以获取到api的返回结果。
如若是获取root用户当前密码或者重置root用户当前密码的api。那么可能直接对方就获取到了root权限。
防重放方案v1 :
方案 :
其实很简单,在服务器端存储一个随机数集,每个随机数只能使用一次,组件在1,2步骤中加一个步骤 : 查询随机数是否处于随机数集中,如若存在,返回重复随机数错误,如若不存在将其则加入随机数集。
为什么方案有效 :
由于会进行签名检验,故而如若你抓到包,然后更改为一个未曾使用过的随机数 + api参数 + code,即使api参数不变,code也不可能与随机数 + api参数的签名结果相同。
新的问题 :
由于有些api可能是间隔时间访问,例如 : 获取组件的运行状态。
如若不清除随机数集 那么势必会导致 随机数 不够用,由于查询 随机数 时间过长导致api访问失败。甚至 磁盘被写满(假设随机数足够长)。
防重放方案v2 :
方案 :
随机数集中的随机数具有有效期,且定期清除。
避免的问题 :
定期清除避免v1的几乎所有问题,如若设置一个月甚至半年的有效期,也不存在太大的安全隐患(一般没人留着包等半年后去攻击你,但不排除这种可能性)。
问题 :
查询时间长,占用磁盘的旧问题并未完全解决,如若遇到高频率访问的api完全有可能重现这些问题。
新问题 : 有效期后的重放攻击无法避免。
防重放方案v3 :
云平台 :
1) 云平台生成一个随机数 rand,记录当前时间time ,将rand + time + api参数一起进行哈希然后利用秘钥进行加密(类似于签名)生成一个code,然后rand + time + api参数 + code发送给客户端。
2) 经过SSL加密到达服务端
组件 :
1) 从SSL取得解密的数据
2) 检测 time 与服务端当前时间是否超过 2 * TTL。
3) 将rand + time + api参数一起进行哈希然后利用秘钥进行加密(类似于签名)生成另一个code与收到的code进行比对。
4) 遍历检测当前随机数集是否存在超出有效期(2*TTL)的随机数,如若有则删除。
3) 遍历检测当前随机数集是否存在rand。
4) 将rand和time写入随机数集。
5) 提供服务并返回结果。
原理 :
1) 利用签名保证了 time 和 rand 的可靠性。
2) 利用 time 排除了time < server_time 和 time > server_time + 2*TTL 的包。
3) 利用 具有有效期的随机数集 保证了 在 server_time <= time <= server_time + 2*TTL 内的包 rand 不重复。
优势 :
维护的 具有有效期的随机数集 小,所以不会因为鉴权导致更高的时间与空间上的过度浪费,安全。