JWT 应该存储在 localStorage 还是 cookie 中?

为了使用 JWT 保护 REST API,根据某些材料(如 向导有个问题) ,JWT 可以存储在 本地存储饼干中。据我所知:

  • LocalStorage 受制于 XSS,通常不建议在其中存储任何敏感信息。
  • 使用 饼干,我们可以应用“ httpOnly”标志,从而降低 XSS 的风险。但是,如果我们要在后端从 Cookies 读取 JWT,那么我们将受到 CSRF 的约束。

因此,基于上述前提——最好将 JWT 存储在 Cookies 中。对于每个对服务器的请求,JWT 将从 Cookies 中读取,并使用 Bearer 方案添加到 Authorization 头中。然后服务器可以验证请求头中的 JWT (而不是从 cookie 中读取)。

我的理解正确吗?如果是,上述方法是否有任何安全问题?或者实际上我们可以从一开始就不用使用 localStorage?

100210 次浏览

一个及时的 来自 Stormpath 的邮件已经很好地阐述了我的观点并回答了我的问题。

DR

将 JWT 存储在 cookie 中,然后像我提到的那样在每个请求的 Authorization 头中传递 JWT,或者像文章建议的那样,依靠后端来防止 CSRF (例如,在使用 Angular 时使用 xsrfToken)。

我喜欢文章中提到的 XSRF Double Submit Cookies 方法@pkid169,但是有一点文章没有告诉你。您仍然没有得到针对 XSS 的保护,因为攻击者可以注入脚本来读取您的 CSRF cookie (不是 HttpOnly) ,然后使用这个 CSRF 令牌向您的 API 端点发出请求,并自动发送 JWT cookie。

因此,实际上您仍然容易受到 XSS 的影响,只是攻击者不能窃取您的 JWT 令牌以供以后使用,但是他仍然可以使用 XSS 代表您的用户发出请求。

无论是将 JWT 存储在 localStorage 中,还是将 XSRF 标记存储在非 http-only cookie 中,XSS 都可以轻松地获取这两种标记。甚至 HttpOnly cookie 中的 JWT 也可能受到高级 XSS 攻击。

因此,除了 Double Submit Cookies 方法之外,您还必须始终遵循针对 XSS 的最佳实践,包括转义内容。这意味着删除任何可执行代码,这些代码会导致浏览器做一些您不希望它做的事情。通常这意味着删除//< ![ CDATA [导致计算 JavaScript 的标记和 HTML 属性。

为了帮助防止利用现有 cookie 的 CSRF 攻击,您可以使用 SameSite指令设置 cookie。设置为 laxstrict

这仍然是 草稿和2019年的 当前所有浏览器不完全支持,但取决于您的数据的敏感性和/或您对您的用户使用的浏览器的控制,这可能是一个可行的选择。使用 SameSite=lax设置指令将允许“使用‘ safe’... HTTP 方法的顶级导航”

  • 不要将令牌存储在 LocalStorage 或 SessionStorage 中,因为这样的令牌可以从 javascript 读取,因此容易受到 XSS 攻击。
  • 不要把你的代币存储在 Cookie 里。Cookie (带有 HttpOnly 标志)是一个更好的选择——它容易受到 XSS 攻击,但是容易受到 CSRF 攻击

相反,在登录时,您可以交付两个令牌: 访问令牌和刷新令牌。访问令牌应该存储在 Javascript 内存中,刷新令牌应该存储在 HttpOnly Cookie 中。刷新令牌仅用于创建新的访问令牌,仅此而已。

当用户打开新选项卡或在现场刷新时,您需要根据 Cookie 中存储的刷新令牌执行创建新访问令牌的请求。

我也强烈推荐阅读这篇文章: https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/