如何保护刷新令牌?

dux*_*x-- 12 access-token oauth-2.0 refresh-token

我正在使用 JWT 对我的应用程序的用户进行身份验证。当用户登录时,他们会获得一个访问令牌和一个刷新令牌。为了保证刷新令牌的安全,我不会将其存储在客户端,而是将其与他们的帐户一起保存在后端,因此不容易访问。不过,我对刷新令牌的安全性感到困惑,这是我在阅读有关如何使用刷新令牌的在线资源时所理解的逻辑:

  1. 认证
  2. 将访问令牌 + 刷新令牌存储在某处(在我的情况下,前端的访问令牌和后端的刷新令牌)
  3. 执行 api 请求时,在 api 端验证访问令牌
  4. 如果访问令牌过期,使用刷新令牌生成新的访问令牌+新的刷新令牌,将访问令牌发送回客户端
  5. 像以前一样存储令牌......并重复

我担心的安全问题是,如果其他人(黑客)获得了访问令牌并使用它向 api 发送请求,如果令牌已过期,api 将使用刷新令牌来获得新的访问权限令牌 + 新的刷新令牌,并至少将访问令牌返回给黑客。

我读了这篇文章大约 5-6 次,我读了几遍这篇文章,以及一些关于这个主题的其他文章,他们都说了一些类似的话

确保安全地存储刷新令牌,因为它是长期存在的,access_token 是短暂的,所以没什么大不了的

但是根据我上面描述的流程,访问令牌是否是短暂的并不重要,刷新令牌将用于获取新的访问令牌并永久访问。

有什么我想念的吗?如果黑客持有过期的访问令牌,api 如何知道谁在发送请求?它仍然会使用刷新令牌发送一个新的。我应该以某种方式验证谁在发送请求吗?


更新

所以我明白,当请求新的访问令牌时,我需要发送刷新令牌、客户端 ID 和客户端机密。我遇到的问题是,像以前一样,黑客可以向我的 API 服务器发送请求,服务器从黑客那里获取被劫持的访问令牌,它会看到它已过期,因此它将发送刷新令牌,以及将 clientID/client 机密(存储为环境变量)发送到 Auth API 并取回新的访问令牌/刷新令牌,这使我们回到了同样的问题。


更新 2

关于这个主题的一些有趣的问题:

  1. 为什么 OAuth v2 有访问令牌和刷新令牌?
  2. https://security.stackexchange.com/questions/87119/how-secure-are-expiring-tokens-and-refresh-tokens

根据第二个问题和答案,似乎刷新令牌不是一种更安全的维护访问方式,只是更容易检测到黑客,因为不断请求身份验证/刷新令牌并使对方的令牌无效。问题是这只会在 2 个用户同时尝试访问资源时发生 - 如果只有黑客碰巧在给定时间段内处于活动状态,他将可以无限制地访问原始用户数据,直到原始用户尝试使用应用程序并访问受保护的资源

dux*_*x-- 18

基本上,在基于浏览器的应用程序中使用刷新令牌似乎是一个坏主意。刷新令牌适用于可以将刷新令牌安全地存储在手机上的移动应用程序 - 手机具有某种安全存储机制,而浏览器则没有。


可以对此答案进行改进。虽然我个人仍然认为在浏览器存储中存储访问令牌或刷新令牌是不安全的(在阅读了许多关于该主题的文章之后,即使许多人仍然这样做),localstorage 中的短期访问令牌 + 内存刷新令牌可以极大地改善用户体验。这样,只要用户不进行硬刷新,或离开网站/web 应用程序,他们就会无限期地登录。

  • 我不同意。刷新令牌可以在服务器上失效,也可以与 DeviceId 一起使用,保存在 httponly cookie 中。如果新访问令牌的请求带有刷新令牌但不是正确的 DeviceId,则服务器可以拒绝它。这是当今许多身份验证系统的基本机制。这就是为什么您会在很多系统上看到“我看到您正在从新设备登录”消息,并且效果非常好。 (3认同)
  • 据我了解,刷新令牌是否应该位于客户端才能刷新访问令牌?否则,如何刷新访问令牌?而且它也是一种失效机制,因此用户的密码已更改,然后会发出新的刷新令牌,因此旧的令牌不再有效。我同意很多讨论似乎都以不同的方式进行,并且没有真正的解决方案。这是我发现的关于在客户端存储刷新令牌的文章:https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/#jwt_persist (2认同)

Ján*_*aša 5

有一个很好的文档OAuth 2.0 for Browser-Based Apps讨论了这些应用程序的最佳实践。

我会选择将令牌保留在客户端或服务器上。混合它(在服务器上保留刷新令牌并在浏览器中保留访问令牌),您可以创建自己的具有自身漏洞的协议。

如果浏览器应用程序需要访问令牌只是为了访问其后端,您可以考虑使用后端作为 OAuth2 客户端(接收身份验证代码),获取用户的身份,发出一个 cookie,该 cookie 将维护浏览器和浏览器之间的会话后端。它比交换、刷新和验证 OAuth2 令牌容易得多。

如果您确实希望将浏览器应用程序保留为接收令牌的 OAuth2 客户端,则应使用PKCE 扩展(因此网络缓存和浏览器历史记录中保存的身份验证代码不能用于获取令牌),并为每个新的刷新令牌获取一个新的刷新令牌。访问令牌 - 查看有关刷新令牌的章节

授权服务器不应向基于浏览器的应用程序颁发刷新令牌。

如果授权服务器确实选择向基于浏览器的应用程序颁发刷新令牌,则它必须在每个访问令牌刷新响应中颁发新的刷新令牌。这样做可以减轻刷新令牌泄漏的风险,因为如果攻击者和合法客户端都尝试使用相同的刷新令牌,则可以检测到泄漏的刷新令牌。

您的浏览器应用程序可以保留其令牌,sessionStorage以便在页面重新加载后继续存在。