我想知道在更改密码/注销时使 JWT 无效而不击中 db 的最佳实践。
我有以下想法通过访问用户数据库来处理上述两种情况。1.如果密码更改,我检查存储在用户数据库中的密码(散列) 2.如果注销,我将上次注销时间保存在用户数据库中,因此通过比较令牌创建时间和注销时间,我可以使本案无效。
但这两种情况的代价是每次用户点击 api 时都会点击用户 db。任何最佳实践都值得赞赏。
我想知道在更改密码/注销时使 JWT 无效而不击中 db 的最佳实践。
我有以下想法通过访问用户数据库来处理上述两种情况。1.如果密码更改,我检查存储在用户数据库中的密码(散列) 2.如果注销,我将上次注销时间保存在用户数据库中,因此通过比较令牌创建时间和注销时间,我可以使本案无效。
但这两种情况的代价是每次用户点击 api 时都会点击用户 db。任何最佳实践都值得赞赏。
除非您正在访问数据库,否则没有解决方案。您可以将查找次数减少到一次而不是两次。
更改密码或注销后,您将 CSPRNG 生成的 128 位数字写入用户表中该用户的行。
这个 CSPRNG 是 JWT 的一部分。在每次访问时,您都需要检查 JWT 中的数字是否与数据库中存储的值匹配。在这个值上计算 MAC 也没有任何优势,我们只是将它保存在 JWT 中,所以一切都在一个地方。
这种排序首先违背了使用 JWT 的目的——您不妨简单地使用在服务器端检查的会话令牌。但好处是您不需要在服务器端维护单独的会话,因为一旦 JWT 过期,它就已经过期,因为您不会接受任何过期日期过去的会话。
另一个缺点是,如果有两个会话针对同一个用户,注销一个会注销另一个。此外,逻辑比服务器端托管系统更复杂,额外的复杂性往往会降低安全性。
JWT 最佳实践是根本不使用数据库或缓存,JWT 的整个想法是无状态验证检查,您可以将用户 ID 存储在令牌有效负载中,并在需要时由多台机器使用,而无需同步会话 ID 或一样。
确保使用长且随机的用户 ID,因此如果攻击者设法伪造令牌,他只会冒一个用户的风险,并且无法访问其他用户,这与顺序 ID 不同。
您可以为您的 JWT 令牌使用较短的生存时间并让它们频繁更新,并使用一种机制来禁止更新较旧的 JWT 令牌。您需要 JWT 中的自动更新令牌,可以将其与您存储在数据库中的内容进行比较。这至少意味着您只为每个更新周期访问数据库。您可以将其设置为 5 分钟,这将比每个客户端到 Web 事务的流量少很多。
但是,仔细想想,这是一个维护成本很高的解决方案。只有极少数用户实际上会要求退出所有设备。
建议的解决方案:
如果你想告诉代理不要再信任少数几个 ID,你会怎么做?也许您会要求他们不时与您核对以更新他们的“黑名单”记录。现在您只有少数“无状态”Web 服务每 x 分钟检查一次更新。您只需要保留尚未过期的主动失效的 JWT 令牌的黑名单。
我想你会发现这个解决方案可以扩展,通常不需要立即使令牌过期。即使您这样做了,您也可能为时已晚提出使所有令牌无效的请求,那么 60 秒有什么区别呢?如果您需要执行一项非常关键的操作(发射核武器?) - 也许您应该要求您的最终用户实时重新验证该操作!
我不相信有任何方法可以在不检查每个请求的数据库的情况下使 JWT 无效。
最好的办法可能是颁发访问令牌 JWT 的有效期很短,然后在需要更新访问令牌时使用刷新令牌。
这样,虽然不能立即使令牌失效,但至少它只能在过期之前使用。使用刷新令牌时,您的授权代码可以决定是否应该发布新的访问令牌。
只是好奇,为什么仅仅因为密码更改就需要使 JWT 无效?那时有什么理由强制注销吗?JWT 不包含密码,因此更改的密码不应该对 JWT 产生任何影响。
您唯一需要使用户无效的情况是他们的权限已被更改或撤销。
注销通常是用户发起的操作,在这种情况下,客户端可以简单地清除/重置/删除它当前为用户拥有的 JWT 令牌。