likes
comments
collection
share

API防止重放的设计和思考

作者站长头像
站长
· 阅读数 6

最近公司有一个需求,需要针对来访请求增加防重放攻击策略,这算是一种安全架构上的设计,相信肯定很多公司都已经按照自身的也去情况进行了实现,每个公司肯定也有自己的做法,但是可以肯定的是,像这种安全架构层面上的东西大公司一般都不会泄露。网上参考来参考去也就那几种,下面是我摘抄来自 API接口防止重放攻击(重复攻击)的内容。

定义

我们在进行API接口设计时,一般都要考虑接口的防止篡改攻击和防止重放攻击。重放攻击(Replay Attacks)又称重播攻击、回放攻击,是指攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。重放攻击可以由发起者,也可以由拦截并重发该数据的敌方进行。攻击者利用网络监听或者其他方式盗取认证凭据,之后再把它重新发给认证服务器。重放攻击在任何网络通过程中都可能发生,是计算机世界黑客常用的攻击方式之一。

举个例子,用户发起一个付款请求,请求中带着付款参数,攻击者拦截了该请求,向服务器重复的发送该请求,如果服务器端没有配置防止重放攻击策略,则可能会进行多次付款,造成用户损失。

常用的防止重放攻击策略主要分为以下三种:

1、基于 timestamp 的方案

2、基于 token 的方案

3、基于 timestamp 和 token 的方案

基于 timestamp 的方案

在请求中增加 timestamp 参数要来表示请求时间戳,服务方端接收该请求后,根据当前时间生成一个接收时间戳,然后根据两个时间戳的差值进行请求判定,如果差值大于指定的阈值,则认为请求无效,否则请求通过。关于阈值的选定,可以根据接口的响应速度进行适当的调整,一般默认为 60 秒。

伪代码如下:

if((接收时间戳-请求时间戳) > 60){
	"请求失败"
} else {
	"请求通过"
}

该方案要求请求和响应的双方必须进行时间同步,如果服务的双方本身存在时间上的差异,会对差值的计算产生影响,最后导致请求的判定产生偏差。

缺点:通过上面的判定逻辑可以发现,在小于阈值的时间段内是可以进行重复请求的,该方案不能保证请求仅一次有效。

基于 token 的方案

在请求中增加一个通过指定规则产生的 token,标识请求的唯一性,服务方接收该请求后,先判断缓存集合中是否存在该 token,如果存在则认为此次请求无效,否则将 token 放入缓存中,通过请求通过。

伪代码如下:

if(token 存在于缓存集合中){
	"请求失败"
} else {
	将 token 放入集合中
	"请求通过"
}

该方案要求 token 的生成规则要保证唯一性,如果 token 值重复,则会影响正常的请求访问。

缺点:token 存在于缓存中,而且没有有效期设置,随着请求量的增加,缓存集合中 token 的数量会非常庞大,会占用系统的大量内存。为了解决这个问题,我们引入了基于 timestamp 和 token 的方案。

基于 timestamp 和 token 的方案

timestamp 解决 token 方案中缓存集合数据量大的问题,token 解决 timestamp 方案中一次性访问的问题。伪代码如下:

if((接收时间戳-请求时间戳) > 60秒){
	"请求失败"
} 

if(token 存在于缓存集合中){
	"请求失败"
} else {
	将 token 放入集合中,缓存时间60
	"请求通过"
}


通过此种方式改进,即解决了验证token一次性问题,又解决了token缓存的有效期问题。

总结

我个人想法:

第一种基于timestamp方案最大的问题是客户端所处的不同时区时间是不一样的,服务器肯定都是以一个时区的时间进行比较的,但是客户端时区却是很多的,并且客户端会随着时区不一样获得的时间也不一样;如果一定要使用这种方式,还得在客户端传入所处的时区,然后服务端按照时区获得时间进行比较,这对于服务端开发来说也是一个挑战。

第二种和第三种其实没有差太多,一个token缓存有过期时间,一个没有过期时间的区别,这种两种方案最大的挑战是存放token的redis可能成为一个瓶颈。就拿日均流量1000万PV的系统来说,每秒钟就有115条token缓存产生,假设token缓存的有效时间为60s,那么每60s将会有约7000条缓存产生和过期,这对于redis来说也是一个挑战。

我们的选择,我们选择的是第三种方式。主要基于以下几点考虑:1、我们的流量,整体项目日均pv在200w左右,峰值也不会查过1000w。2、我们将这种token缓存放在redis,并且在阿里云购买了可伸缩的redis服务,好处就是可以支持横向扩容、对服务无感知,万一流量来了,我们就在买一台,3、开发成本简单、可控,只需要我们在当前的getway程序中把这个功能加上去即可。

最后,大规模、高并发项目究竟该如何实现api防重放呢?