在数据库中存储和维护 JWT 刷新令牌的最佳策略?

Posted

技术标签:

【中文标题】在数据库中存储和维护 JWT 刷新令牌的最佳策略?【英文标题】:Best strategy for storing and maintaining JWT refresh tokens in the database? 【发布时间】:2020-12-18 15:05:39 【问题描述】:

我有一个通过后端实现 JWT 身份验证的移动应用。访问令牌是短暂的 (1h) 并且不存储在后端。现在是刷新令牌:

    如果刷新令牌过期,则意味着用户将被定期注销,这从业务角度来看是非常不可取的,它可能会损害用户保留率。有没有办法在不削弱安全性的情况下避免这种情况,例如使刷新令牌“永恒”?

    存储和清理可防止未使用令牌累积的刷新令牌表的最佳方法是什么?假设我有以下表结构:user_iddevice_idrefresh_token。如果策略是使刷新令牌永不过期,那么使它们失效的唯一方法是在用户注销时。但是,用户也可以删除应用程序、丢失或损坏设备,或者出于任何原因更改其device_id。我能想到的一种解决方案是有一个refreshed_at 时间戳,这将允许在几个月不使用后使令牌失效。还有其他已知的技巧吗?

    假设我在刷新访问令牌时除了刷新令牌之外还使用了共享密钥字符串,我的理解是否正确,即如果所有 3 个都受到损害(访问令牌、刷新令牌和共享密钥),我对此无能为力吗? refresh API 调用的最佳做法是什么?

【问题讨论】:

【参考方案1】:

永久刷新令牌确实会增加风险。为了抵消这一点,您可以削弱在刷新期间发布的令牌。为此,您可以在范围上设置过期时间。然后,随着刷新的发生,新令牌的范围越来越少。稍后,如果用户试图做一些高风险的事情,他们将不得不再次登录并证明对他们原始凭证的控制。我认为企业可能会接受这一点。 (More on this idea 可以在这里找到。)

您保留refreshed_at 的想法可能是避免刷新令牌表永久增长的方法。如果用户确实注销,您不能删除刷新令牌吗?会有一些注销端点,所以在后面进行清理。这样一来,您的refreshed_at 仅适用于夹缝中的东西。

我看不出秘密字符串有什么帮助。它本质上是另一个“令牌”,都是不记名令牌,所以我会跳过这个。有关保护威胁免受刷新流影响的更多信息,请查看 section 4.5 of RFC 6819。另外,请查看 section 4.12 of the OAuth security BCP(这只是一个 RFC)。

【讨论】:

谢谢,很有用!用户并不总是注销,他们也可以在不注销的情况下删除应用程序,这种情况经常发生。同样,对于网络客户端,人们倾向于清理 cookie 和其他存储,在最新的 Safari 版本中,cookie 也会以某种方式自行消失 - 我仍然无法弄清楚为什么会发生这种情况。所以refreshed_at 假设几个月大(取决于您的应用程序的性质)当您可以安全地删除记录时可能是一个好点,我在想。 检查这个答案:***.com/a/58652141/150435 在一些旧的 Safari 版本中存在一个错误,其中 SameSite=None 被视为 SameSite=Strict 要解决这个问题,您可能必须进行浏览器检测。【参考方案2】:

基于过去曾与 Ping Federate 合作并使用过他们的实现,要补充几点:

存储刷新令牌 SHA256 哈希而不是令牌本身,这样任何流氓员工都无法窃取和使用刷新令牌

包括client_id 和issued_at / expires_at 字段。这使管理员能够按应用程序、用户和时间查找和撤销刷新令牌。

【讨论】:

散列的好主意!

以上是关于在数据库中存储和维护 JWT 刷新令牌的最佳策略?的主要内容,如果未能解决你的问题,请参考以下文章

委托刷新令牌获取新JWT的基本策略

同时从移动设备和 Web 刷新 JWT 令牌的最佳实践

如何在前端和后端存储 JWT 刷新令牌?

JWT 刷新和访问令牌

在 Django REST 框架中使用 JWT 时,刷新令牌和访问令牌存储在哪里?

jwt 访问令牌和刷新令牌流