上一章节,为了防篡改,我们给第一个请求增加了签名和验签,这样就可以解决数据防篡改问题。你觉得这样就安全了吗?我们看,同一接口,同样的参数,同样的签名值,是不是每次调用,都是可以成功的。如果被恶意利用,非法用户疯狂的调用这一个接口呢,服务器资源是不是就浪费了,如果这个接口业务比较复杂,还要操作数据库,正好操作数据库也耗时,那是不是有可能给搞的当机了。

那有没有办法解决这个问题呢,当然有。比如再给每一个请求加上一个时间戳,并且时间戳也加入签名防篡改,是不是可以先验证这个请求是什么时候发起的,有没有超过指定时间(比如3分钟),超过就直接丢弃。

比如这个接口:

curl -v -H 'X-TimeStamp: 1680503150' 'http://127.0.0.1:8080/testGet?p=testp&ab=123&x=456'
1

我们在Header里,多传了一个X-TimeStamp,值为距离1970-01-01的UTC秒数,为了防止别人篡改呢,也需要将其作为签名的数据,比如固定参数名为timestamp,放置在path后面,也不参与排序,那么待签名数据就变成了:

ab=123&p=testp&x=456&path=/testGet&timestamp=1680503150
1

# 遗留问题

  • 加入时间戳后,可以有效的防止重放,但有效期内请求仍然有效,所以需要加入其它方案来增强,比如限流。又比如后续讲到的nonce。
  • 时间戳有一个客户端与服务器时间可能会不同步的问题,所以多少分钟内有效,要根据业务需要来定。另外也可以在服务器加入获取服务器当前时间的接口,来同步客户端与服务端的时间。
  • 如果加了获取服务器时间这种无状态的接口,也要考虑加入签名及验签机制,或者限流机制,防止攻击。