前后端分离的项目, API 接口如何防止重放攻击

2017-07-29 15:21:23 +08:00
 lemayi
当前的项目是前后端分离的,用了 laravel 的 jwt 做 token 验证。
看过很多文档都说用时间戳 timestamp 和 nonstr 来做。
但是客户端的时间戳没办法保证和服务器的一致。
每个用户的可能时区都不一样。没办法通过传递时间戳参数来验证是否过期。
如果只用 nonstr,如果设置 1 天清除一次。那么一天后重放也是可以的。
所以想请教下怎么来处理这个问题呢?
20089 次点击
所在节点    问与答
19 条回复
shoaly
2017-07-29 16:10:49 +08:00
客户端传给服务器
?nonstr=md5(时间戳 +随机数+ 特定字符串)&time=时间戳&random=随机数

服务器端:
验证 md5(用客户端传入的时间戳+ 随机数+特定字符串) 与 nonstr 对比 验证是否是客户端的请求, 然后将这个 nonstr 存入缓存当中, 同一个 nonstr 如果已经存在, 则为重放攻击
shoaly
2017-07-29 16:11:42 +08:00
补充 1 天之后的重放, ..时间戳能对比出来啊.... 客户端确实和服务器端时间不一致, 但是 差不了几秒.
retanoj
2017-07-29 16:16:38 +08:00
为什么时间戳无法保证和服务器一致? 难道不是在用格林尼治时间吗? timestamp 加签名应该可以解决重放了
des
2017-07-29 16:31:03 +08:00
时间差?就不能请求获得服务器时间,然后基于这个时间戳校正吗,如果出错就先获取一次时间戳再请求一次。

总不能客户端的一分钟被人偷走一秒吧?
nealv2ex
2017-07-29 16:39:50 +08:00
单纯的放重放来说 ,全不用不管与服务器的差值,只看时间戳就可以,时间是线性增大,不会变小,如果不变或者变小了,就有问题。

收到请求,校验时间戳必须比上一次 这个 session 的提交的时间戳大。

比如
第一次是 0,第二次 1 在过滤重放攻击这个条件下,这 2 个值都是合法的。
ho121
2017-07-29 16:53:24 +08:00
@nealv2ex 改时间怎么办?
danielmiao
2017-07-29 17:02:28 +08:00
令牌桶,客户端请求的时候判断超过 x 分钟,更新令牌;
然后旧令牌的失效时间为,更新令牌的时间+[0.2, 1] * x,以保证正常的并发请求;

简单的说就是动态发放令牌,有效令牌为当前发放和有效期内的旧令牌,最好使用 cookie,保证对页面的无侵入
danielmiao
2017-07-29 17:03:22 +08:00
@nealv2ex 这个方案有个问题就是 ajax 并发请求的时候,后发先置的问题
paradoxs
2017-07-29 17:11:37 +08:00
参照 google authy 的验证机制, 把随机数发生器内置在前端就行了。
nealv2ex
2017-07-29 17:42:35 +08:00
@ho121 改时间,就不是 *重放* 攻击了。

@danielmiao 这里只解决 *重放*,后发先至是其他问题。

不过请思考一下,后发的请求已经到了,那么是不是说,

客户端取消了先发的请求,要不然哪里来的后发请求,

那么我只处理后发的请求,不处理先发的请求应该是合理的。
lemayi
2017-07-29 18:15:37 +08:00
感谢各位的解答!非常感谢!
@nealv2ex 的回答,之前我也有考虑。但是确实会有并发,后发先至的问题。既然是并发,先发,后发的请求都肯定是合理。如果参考你的处理的方式,肯定就排除掉了正常的请求。

@shoaly @des @retanoj 因为是前后端分离的 web 项目。js 生成的时间戳应该是本地时间。所以这个时间是很有可能和服务器不一致的。跨时区,篡改等。我之前做过测试。在服务器端放个含时间 js 的 html。然后去请求。确实打印出来的时间是我本地的时间。我电脑改了。显示的时间也改变了。其实我问的问题,主要就是纠结于此。如果是在后端的程序请求 api 那就没这个问题。我可以让客户端设置成和服务器端的一致。

@danielmiao 的方式令我思路大开。因为当前用的是 jwt 的 token。那么我可以让前端,每 30 分钟就去重新刷新获取新的 token。然后配置每次请求用 nonstr 来防止重发。记录 30 分钟内的 nonstr 集合。不在这个集合里面就是正常请求。这样即使过了 30 分钟,发起重放。实际上我的 token 已经变了。就没这个问题了。也不会有时间戳一致的问题了。
plantain
2017-07-29 18:23:42 +08:00
标准方法难道不是 https ?
des
2017-07-29 18:42:03 +08:00
@lemayi 一开始以为是客户端,web 的话上 https 啊,不然重放都是小问题
motian
2017-07-29 18:50:26 +08:00
时间戳本身是跟时区无关的,你在东八区和零时区,不同的是日期时间,时间戳是一致的,客户端和服务端的时间差问题可以进行定期的时间校准。
retanoj
2017-07-29 22:27:26 +08:00
不过 lz,jwt 里有个字段是标识请求仅一次有效的啊,好像是 iat ?可以参考一下
whileFalse
2017-07-29 22:29:40 +08:00
你要防止的是啥?中间人重放的话上 https 就行
lianz
2017-07-29 22:34:42 +08:00
timestamp=int(timestamp()/30),这样服务器客户端时间误差 30 秒内就可以满足条件。

当然请求签名是一定要做的,不然一切白费。
voocel
2017-07-29 22:45:25 +08:00
请问用的是哪个 jwt 包
lemayi
2017-07-30 11:25:54 +08:00
@voocel "tymon/jwt-auth": "^1.0@dev"

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

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

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

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

© 2021 V2EX