Go实现防重放攻击

重放攻击

API重放攻击(Replay Attacks)又称重播攻击、回放攻击。他的原理就是把之前窃听到的数据原封不动的重新发送给接收方HTTPS并不能防止这种攻击,虽然传输的数据是经过加密的,窃听者无法得到数据的准确定义,但是可以从请求的接收方地址分析出这些数据的作用。

比如用户登录请求时攻击者虽然无法窃听密码,但是却可以截取加密后的口令然后将其重放,从而利用这种方式进行有效的攻击。

比如给自己账号充值1000元,如果能窃听到这个命令并进行不停重放发送给服务器,那么自己账户上的金额将不停增加

首先要明确一个事情,重放攻击是二次请求,黑客通过抓包获取到了请求的HTTP报文,然后黑客自己编写了一个类似的HTTP请求,发送给服务器。也就是说服务器处理了两个请求,先处理了正常的HTTP请求,然后又处理了黑客发送的篡改过的HTTP请求

解决方案

根据时间戳的方案

每次HTTP请求,都需要加上timestamp参数,然后把timestamp和其他参数加密到token里。因为一次正常的HTTP请求,从发出到达服务器一般都不会超过60s,所以服务器收到HTTP请求之后,首先判断时间戳参数与当前时间相比较,是否超过了60s,如果超过了则认为是非法的请求

一般情况下,黑客从抓包重放请求耗时远远超过了60s,所以此时请求中的stime参数已经失效了。

但这种方式的漏洞也是显而易见的,如果在60s之内进行重放攻击,那就没办法了,所以这种方式不能保证请求仅一次有效

基于应答式的方案

每次请求前,会先去服务器会根据时间戳获取一个随机数,服务器就会将随机数放在缓存中,在请求时参数带上随机数,将随机数加密在token里,服务器就会校验缓存中是否有随机数,有的话就通过并且删除随机数,没有则认为是非法请求。

并且服务器缓存的随机数设置一个60秒的存活时间,防止客户端拿到随机数后不进行后续操作导致随机数在缓存无法被清除而累积的问题

Go实现防重放攻击

使用基于应答式的方案实现防重放攻击

获取随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func PutRandom(c *gin.Context) {
value, err := setRandom()
if err != nil {
c.JSON(400,fmt.Sprintf("redis set random err:%v", err))
return
}
c.JSON(200, value)
}

func setRandom() (string, error) {
rand.Seed(time.Now().UnixNano()) // 设置纳秒级别的随机数
random := rand.Intn(math.MaxInt32)
str := strconv.Itoa(random)
if _, err := Redis.Set(str, "true", time.Second*60).Result(); err != nil { // 设置随机数存活时间为60s
return "", err
}
return str, nil
}

校验随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func CheckRandom(c *gin.Context) {
v := c.GetHeader("random") // 也可以存在token里
if err := checkRandom(v); err != nil {
c.JSON(400, "random verify fail") // 检验失败
return
}
c.JSON(200, "random verify success")
}

func checkRandom(val string) error {
if _, err := Redis.Get(val).Result(); err != nil {
return err // 没有查到随机数则返回失败
}
client.Del(val) // 检验成功后删除随机数,防止重放攻击
return nil
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!