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

Should JWT be stored in localStorage or cookie?

为了使用 JWT 保护 REST API,根据一些材料(例如 guide and this question),JWT 可以存储在 localStorageCookies。根据我的理解:

所以基于上面的前提——如果我们把JWT存储在Cookies中会是最好的。在对服务器的每个请求中,JWT 将从 Cookies 中读取并使用 Bearer 方案添加到授权 header 中。然后服务器可以验证请求中的 JWT header(而不是从 cookie 中读取它)。

我的理解对吗?如果是这样,上述方法是否有任何安全问题?还是实际上我们可以一开始就使用 localStorage?

一个及时的post from Stormpath已经详细阐述了我的观点并回答了我的问题。

TL;DR

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

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

所以实际上你仍然容易受到 XSS 攻击,只是攻击者无法窃取你的 JWT 令牌供以后使用,但他仍然可以使用 XSS 代表你的用户发出请求。

无论是将 JWT 存储在 localStorage 中,还是将 XSRF-token 存储在非 http-only cookie 中,两者都可以很容易地被 XSS 捕获。甚至你在 HttpOnly cookie 中的 JWT 也可以被高级 XSS 攻击抓取。

因此,除了双重提交 Cookie 方法之外,您还必须始终遵循针对 XSS 的最佳实践,包括转义内容。这意味着删除任何会导致浏览器执行您不​​希望它执行的操作的可执行代码。通常这意味着删除 //

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

这仍然是 a draft and as of 2019 is not fully supported by all current browsers,但是根据您的数据的敏感性 and/or 您对用户使用的浏览器的控制,这可能是一个可行的选择。使用 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/