在react.js中存储访问令牌的位置?

Tha*_*a S 7 access-token reactjs

我正在Reactjs中构建一个应用程序.在验证access_token之后,我必须进行fetch调用.在注册时,从后端服务器获取access_token.但是,在哪里存储这些access_token.是否有任何方法可以使这些access_token全局,以便所有组件都可以访问它.我使用过本地存储,缓存和会话存储,但这些不可取.这个问题在过去的几天内得到了解决,任何解决方案.事先提前.

Ano*_*uar 29

可用选项和限制:

有两种类型的选项可用于存储您的令牌:

  1. Web Storage API:它提供 2 种机制:sessionStoragelocalStorage. 存储在此处的数据将始终可供您的 Javascript 代码使用,并且无法从后端访问。因此,例如,您必须手动将其添加到您的请求中的标头中。此存储仅适用于您应用的域,而不适用于子域。这两种机制的主要区别在于数据过期:
  • sessionStorage:数据仅可用于会话(直到浏览器或选项卡关闭)。
  • localStorage: 存储没有到期日期的数据,只能通过 JavaScript 清除,或清除浏览器缓存/本地存储的数据
  1. Cookies:随后续请求自动发送到您的后端。可以控制您的 Javascript 代码的到期时间和可见性。可用于您应用的子域。

在设计身份验证机制时,您必须考虑两个方面:

  • 安全性:访问或身份令牌是敏感信息。要始终考虑的主要攻击类型是跨站点脚本(XSS) 和跨站点请求伪造(CSRF)。
  • 功能需求:浏览器关闭时用户是否应该保持登录状态?他的会议将持续多久?等等

出于安全考虑,OWASP不建议将敏感数据存储在 Web 存储中。您可以查看他们的CheatSheetSeries页面。您还可以阅读这篇详细的文章以了解更多详细信息。

原因主要与XSS漏洞有关。如果您的前端不是 100% 抵御 XSS 攻击,那么恶意代码可能会在您的网页中执行,并且可以访问令牌。完全防 XSS 非常困难,因为它可能是由您使用的 Javascript 库之一引起的。

另一方面,如果 Cookie 设置为HttpOnly. 现在 cookie 的问题是它们很容易使您的网站容易受到 CSRF 的攻击。SameSitecookie 可以减轻这种类型的攻击。但是,旧版本的浏览器不支持这种类型的 cookie,因此可以使用其他方法,例如使用状态变量。此 Auth0 文档文章中对此进行了详细说明。

建议的解决方案:

为了安全地存储您的令牌,我建议您使用 2 个 cookie 的组合,如下所述:

JWT 令牌具有以下结构: header.payload.signature

通常,有效载荷中存在有用的信息,例如用户角色(可用于调整/隐藏 UI 的部分)。因此,让该部分对 Javascript 代码可用非常重要。

身份验证流程完成并在后端创建 JWT 令牌后,其想法是:

  1. header.payload部件存储在SameSite SecureCookie 中(因此只能通过 https 使用,并且仍可用于 JS 代码)
  2. signature零件存储在SameSite Secure HttpOnlyCookie 中
  3. 在后端实现一个中间件,以从这 2 个 cookie 中重新构建 JWT 令牌并将其放入标头中: Authorization: Bearer your_token

您可以为 cookie 设置到期时间以满足您的应用程序的要求。

Peter Locke在这篇文章中提出并很好地描述了这个想法。


ran*_*min 9

虽然聚会迟到了,但我想分享我对这个话题的看法。 Anouar 给出了一个很好的答案,包括被认为可以抵御 XSS 的 http-only cookie,指出了 CSRF 漏洞并链接了 Peter Locke 的文章。

但是,就我而言,我需要应用程序 100% 无状态,这意味着我不能使用 cookie。

从安全的角度来看,将访问令牌存储在持久位置(如 localStorage、window 等)是不好的做法。因此,您可以使用 redux(或在 state/context 中构建的 react.js)将 JWT 存储在变量中。这将保护令牌免受上述攻击,但在页面刷新后将其置空。

我为解决这个问题所做的是使用刷新令牌,我将其存储在 localStorage 中(如果您愿意,可以使用会话存储或类似存储)。刷新令牌的唯一目的是获取新的访问令牌,后端确保刷新令牌不被盗(例如,实现一个被检查的计数器)。我将访问令牌保存在缓存中(我的应用程序中的一个变量),一旦由于重新加载而过期或丢失,我会使用刷新令牌来获取新的访问令牌。

显然,这仅在您还构建后端时才有效(或者至少如果后端实现了刷新令牌)。如果您处理未实现刷新令牌等的现有 API,并且无法将访问令牌保存在变量中(由于重新加载时为 null),则您还可以在使用应用程序密钥之前使用应用程序机密对令牌进行加密将它保存到 localStorage (或会话存储,或者...是的,你明白了)。请注意,解密令牌需要一些时间,并且可能会降低您的应用程序的速度。因此,您可以将加密的令牌保存到 localStorage(或...)并在刷新后仅对其解密一次,然后将其保持在状态/redux 变量中,直到您再次刷新/再次从 localStorage 解密等。

关于这个话题的最后一句话:身份验证是应用程序的关键基础设施,虽然有趣的游戏和网上银行之间存在明显的区别(你可能想对那家银行“偏执”,而只“关心”游戏),诸如“localStorage 完全没问题”或“在最坏的情况下会发生什么?1 小时后过期”之类的答案是危险的,而且完全是错误的。机器可以在几秒钟内造成大量损坏,而您不想让这种差距保持开放。如果您懒得保护您的应用程序,也许您想使用现有解决方案而不是构建自己的解决方案。

也就是说,JWT/令牌身份验证对游戏来说是相当新的(几年,但不如开发中的其他主题成熟)。找到可行的解决方案需要一些时间和精力,但让我们继续构建安全的软件,而不是让网络泛滥成灾。

最好的,快乐的编码。

  • 很好的答案,但您永远不应该将刷新令牌存储在本地或会话存储中。服务器是唯一需要读取刷新令牌的服务器,您可以通过将其存储在 HttpOnly 的 cookie 中并将 secure 设置为 true 来实现这一点 (6认同)
  • 惊人的答案!谢谢兰敏:) (2认同)