TL;DR 版本:cookie session 与 jwt 中的数据,是比 server session 更加弱一致性的。
cookie session 与 jwt 的目的,都是为了在 scale 的时候,不 hit db。而是由 server 直接验证,提高 scale 的性能。
它们的缓存作用
首先需要明确一点的是,cookie session 与 jwt 都起着一定程度的缓存作用。
而缓存的目的,就是为了让读多写少的数据可以从架构更简单的存储服务中更高效地取出。
弱一致性与重放攻击的例子
重放攻击的本质也是数据的弱一致性。
两个场景,
一个是非法用户场景,这是个弱一致性的场景
比如一个用户,session 数据格式长这样
{name: 'alsotang', id: 1, is_valid: true, score: 20}
这时候,后端的运营同学发现该用户存在恶意行为,将改用户设成了 {is_valid: false}。
可由于我们的 session 是存放在 cookie 中,server 并不知道这个用户已经被屏蔽了,那么 server 在解析了 session 后,会继续对用户放行。直到某些修改操作涉及 hit db,重新构造 session 为止。
一个是用户积分场景,这是个重放攻击的场景
假设用户要在我们的论坛发了个帖子,这个帖子需要扣除 20 积分,某个板块叫做【我是高级版块】,需要 10 积分才能进入。
发帖前的时间点是 A 时间点,对应的浏览器 cookie 为: cookie111111
发帖后,用户的数据长这个样子
{name: 'alsotang', id: 1, is_valid: true, score: 0}
这时是 B 时间点,对应的浏览器 cookie 被 server 更新为:cookie222222
那么这时,用户访问【我是高级版块】时,会被拒绝。
此时,用户把自己的 cookie 重设为 cookie111111。
server 在接收到之后,解析出的用户 session 仍是
{name: 'alsotang', id: 1, is_valid: true, score: 20}
则顺利进入【我是高级版块】。
为何比 server session 更弱
因为 server session 可以被主动清除。
上述的场景1,运营同学在标记了 alsotang 为恶意用户后,运营后台的程序可以去缓存中主动删除用户的 session。
这时,用户在浏览器不关闭的情况下再次访问,server 会发现缓存中的 session 不存在了,于是从数据库中重新构造一个新 session。
上述的场景2,server session 不会受到类似的攻击。
当然,server session 也不是强一致性的,强一致性涉及事务,对于 server 整体的性能影响太大了。
举个板栗说明,
上述场景2中,用户是个爬虫程序,在同一秒内,不仅先回了帖,还后继发起 10 个请求,访问了【我是高级版块】的10个帖子。那么即使 get 的请求在 post 的请求之后,后者仍然是有机会全部通过的。这种属于牛角尖类型的例子,涉及财务的时候,才能发现它的威力。
再举个板栗,在 CNode 回帖后,帖子的作者是可以得到 5 个积分的。
假如 @i5ting 现在的积分是 5000 个,他正在浏览 CNode。我去回了一下他的帖子,现在他在数据库中是 5005 的积分。 而当他在浏览器不关闭的情况下,在首页看到自己的积分仍然会是 5000 个。其实我是可以在回帖之后去清除他 session 缓存的,但由于积分这个东西,从业务上说,追求个不精确的最终一致性即可。所以 server 也没有去清除。
如何最大程度避免
设计尽可能短的过期时间。
评估一下保存在 cookie session 与 jwt 中的数据经得起多久的不一致时间。
比如上述的场景1,1分钟应该问题不大。
你可以举出场景[1..100]出来,然后根据木桶定理,选择最短的时间作为过期时间。