使用场景 :

  当系统需要与云平台进行对接时,常常会使用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 不重复。

  优势 : 

  维护的 具有有效期的随机数集 小,所以不会因为鉴权导致更高的时间与空间上的过度浪费,安全。