在哪里存储客户端上的刷新令牌?

Rob*_*uch 58 authentication cookies oauth token oauth-2.0

我的 SPA 应用程序使用以下架构(来源):

在此处输入图片说明

这假设我的客户端应用程序知道刷新令牌,因为如果不存在用户凭据(例如电子邮件/密码),我需要它来请求新的访问令牌。

我的问题:我在哪里存储我的客户端应用程序中的刷新令牌?关于这个话题有很多关于 SO 的问题/答案,但关于刷新令牌,答案尚不清楚。

访问令牌和刷新令牌不应存储在本地/会话存储中,因为它们不是任何敏感数据的地方。因此,我会将访问令牌存储在httpOnlycookie 中(即使有 CSRF),无论如何,我对资源服务器的大多数请求都需要它。

但是刷新令牌呢?我不能将它存储在 cookie 中,因为 (1) 它会随着每个请求发送到我的资源服务器,这也使它容易受到 CSRF 的攻击和 (2) 它会发送暴露访问/刷新令牌与相同的攻击向量.

我能想到的解决方案有以下三种:


1) 将刷新令牌存储在内存中的 JavaScript 变量中,这有两个缺点:

  • a) 易受 XSS 攻击(但可能不如本地/会话存储那么明显
  • b) 如果用户关闭浏览器选项卡,它会丢失“会话”

尤其是后一个缺点会导致糟糕的用户体验。


2) 将访问令牌存储在会话存储中,并通过Bearer access_token授权标头将其发送到我的资源服务器。然后我可以使用httpOnlycookie 作为刷新令牌。这有一个我能想到的缺点:

  • a) 每次向资源服务器发出请求时,刷新令牌都会暴露给 CSRF。

3) 将两个令牌保存在httpOnlycookie 中,这具有上述缺点,即两个令牌都暴露于相同的攻击向量。


也许除了我提到的缺点之外还有另一种或更多的方式(请告诉我),但最终一切都归结为我将刷新令牌保存在客户端的什么位置?它是httpOnlycookie 还是内存中的 JS 变量?如果是前者,那么我应该把我的访问令牌放在哪里?

很高兴从熟悉该主题的人那里获得有关如何以最佳方式执行此操作的任何线索。

Vla*_*ykh 37

您可以将加密的令牌安全地存储在HttpOnlycookie 中。

https://medium.com/@sadnub/simple-and-secure-api-authentication-for-spas-e46bcea592ad

如果您担心长寿命的刷新令牌。您可以跳过存储它而根本不使用它。只需将访问令牌保留在内存中,并在访问令牌过期时进行静默登录。

不要使用Implicit流,因为它已经过时了

SPA 最安全的身份验证方式是使用 PKCE 的授权代码

一般来说,使用基于oidc-client 的现有库比自己构建更好。

  • “访问令牌过期时进行静默登录”是什么意思? (23认同)
  • @VladimirSerykh 你是什么意思“正常方式”?你还没有解释如何“默默地”获得任何东西! (7认同)
  • @VladimirSerykh 但是“用户界面如何简单地重新验证用户身份”?如果它要求用户输入密码,那么这不是“静默”;而是“静默”。如果它使用其他令牌,它与刷新令牌有什么不同,它存储在哪里? (4认同)
  • -- 拥有长期访问令牌和基于当前访问令牌“静默”刷新访问令牌之间没有区别。-- 此外,向用户显示登录屏幕并提示输入密码时也没有任何“静默”。--“加密令牌”是什么意思?Cookie 被加密只是为了防止其在前端被修改。修改不会损害访问令牌,因为它已签名。(例如智威汤逊)——这如何才能成为可接受的答案?投反对票。 (4认同)
  • @VladimirSerykh 在会话过期后,您无法在不保留刷新令牌的情况下“静默”获取访问令牌。除非“沉默”,否则您的意思是当请求被拒绝时在他们面前弹出登录页面。 (3认同)
  • 当用户在页面上停留相当长的时间而没有交互时,“访问令牌”就会过期。然后用户执行一些操作,API 会响应“401”。通常,客户端上保存有一个“刷新令牌”。在收到 401 作为响应后,UI 应使用“刷新令牌”刷新“访问令牌”。如果没有“刷新令牌”,则 UI 可以简单地重新验证用户身份并获取新的“访问令牌”。 (2认同)

小智 29

您可以将令牌(访问和刷新)存储为 cookie。但是刷新令牌必须有特殊的路径(例如/refresh)。因此刷新令牌将仅针对对 /refresh url 的请求发送,而不是针对每个请求(如访问令牌)发送。

  • 好的,根据[this](https://mailarchive.ietf.org/arch/msg/oauth/vSmJ0zjQzZFjeFbRz_qpvjfpAeU/)的回答,刷新令牌应该仅与授权服务器交换,以减轻泄漏的风险,所以这是有道理的仅将其发送到 /refresh 端点,即使资源服务器和授权服务器相同。 (4认同)
  • @Chano cookie 仍然会被设置,但当您关闭所有隐身窗口时它们会被清除,因此它不应该影响用户的登录能力。 (3认同)

Win*_*ter 9

将访问令牌存储在会话存储中,并通过承载access_token授权标头将其发送到我的资源服务器。然后我可以使用 httpOnly cookie 作为刷新令牌。我能想到这有一个缺点:a) 每次向资源服务器发出请求时,刷新令牌都会暴露给 CSRF。

您可以正确设置,以便仅接受来自授权服务器的CORS policy请求。/refresh_token

如果客户端和服务器由同一台计算机提供服务,则可以在 中将标志设置sameSite为 trueCookie并包含anti-CSRF令牌。


Jos*_*les 9

如果您的身份验证提供程序实现了刷新令牌轮换,您可以将它们存储在本地存储中。

但这意味着每次客户端刷新 JWT 时,您的 Auth 提供程序都应返回一个新的刷新令牌。如果尝试第二次使用一个刷新令牌,它还应该有一种使后代刷新令牌无效的方法。

https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation