网络请求中使用随机数避免重放攻击的原理是什么?

2021-11-23 01:38:57 +08:00
 Richard14

注意到所有的这些云平台提供的 api ,调用的过程中都需要生成一个随机数,然后根据随机数生成签名。调用百度翻译、腾讯翻译 api 的时候都是如此。据说是为了避免被重放攻击。那么它的原理是什么呢?

第一次能请求成功的话,签名就是合法的,如果这时候第二次进行了完全相同的请求,服务器怎么知道该请求属于重放呢?

疑问一:是默认不同时间生成的随机数完全不同吗?有没有可能刚好两次临近请求生成了相同的随机数?比如一秒内刚好两次生成 9527 这个数。

疑问二:后端如何拦截?难道要维护一个队列,每个 ID 最近三分钟内请求的随机数都有哪些?类似这种的?如果这么搞的话成本不会爆炸吗?

2425 次点击
所在节点    问与答
25 条回复
046569
2021-11-23 12:12:55 +08:00
“第一次能请求成功的话,签名就是合法的,如果这时候第二次进行了完全相同的请求,服务器怎么知道该请求属于重放呢?”
=> 服务器上保存了有效 ID ,请求后立即删除。第二次请求由于 ID 不合法而丢弃。

“疑问一”
=> 各编程语言一般使用伪随机数,即便是相同时间也会生成不同的随机数,是统计学意义上的随机。你可以改用用户输入键盘上字母时间,字母分布等实现更好的随机数。

“疑问二”
=> 如果使用时间过期的策略,那么在有效期内是 **可以** 攻击成功的。成本可以依靠统一的 No SQL 数据库解决。主要目的是不要访问主数据库。

虚拟场景:
攻击者 A 让受害者 B 执行一笔转账且截获了 B 的令牌,A 重新发起转账,此时若使用时间戳策略,A 可以预测未来的时间戳,提前生成并发送造成多次转账,攻击成功。允许五分钟你猜猜能转账成功多少次。

LZ 可以自己搭建个 MIMT 测试环境,然后尝试中间人攻击,这样可以更好的了解攻击者手法。
letitbesqzr
2021-11-23 17:19:13 +08:00
@Chad0000
我觉得时间戳和随机数并不是同一个功能。

时间戳 可以限制请求是 5 分钟内的请求。但是并没办法防止重放攻击啊?意思是允许 5 分钟内的重放? 也不可能限制某个时间戳 只能请求一次吧?
Chad0000
2021-11-23 17:27:10 +08:00
@letitbesqzr #22 校验码 = md5(AppID + RequestData + timestamp + key),然后规定 timestamp 不能重复且必须大于上一次请求,这个检验通过 Redis 实现,只需要存一个就行,缓存的 Key 可以是:AppID 加上固定前缀这种。每次请求验证通过后即可更新此值。甚至如果你愿意你还可以保存在 DB 中,通过 update Table set LastTimeSamp=@0 where Id=AppId and LastTimeStamp<@0 这种更新来确保它是递增的。

要不要严格判断取决于业务被重放的代价。
Chad0000
2021-11-23 17:41:20 +08:00
@letitbesqzr #22 这个 timestamp 实际上与计数器没区别,之所以使用 timestamp 是因为绝大部分场景下调用方使用频率低,推荐他们使用 timestamp 直接无需保存计数器,方便直接。调用多了就考虑让他们使用队列或全局计数器当 timestamp 甚至 IP 白名单适当放宽都可。
daimubai
2022-01-09 21:05:21 +08:00
timestamp+UUID(随机字符串)
前端:签名时将 timestamp 和 UUID 加入一起签名

后端:
首先比较 timestamp ,如果当前时间和 timestamp 相差 5 分钟直接拒掉

如果 timestamp 没毛病,去 redis 查这个 UUID 是否存在,存在的话直接拒掉

UUID 不存在,将 UUID 放入 redis 中,过期时间设置为 5 分钟,同时认为当前请求不是重放攻击。

两者结合,既避免了时间戳 5 分钟的窗口期,又避免了随机字符串的存储量很大

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/817263

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX