Javascript 在基于浏览器的应用程序中保存 JWT 的位置以及如何使用它
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26340275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Where to save a JWT in a browser-based application and how to use it
提问by zero_coding
I'm trying to implement JWT in my authentication system and I have a few questions. To store the token, I could use cookies but it's also possible to use localStorageor sessionStorage.
我正在尝试在我的身份验证系统中实施 JWT,但我有几个问题。为了存储令牌,我可以使用 cookie,但也可以使用localStorage或sessionStorage。
Which would be the best choice?
哪个是最好的选择?
I have read that JWT protects the site from CSRF. However, I can't imagine how that would work assuming I save the JWT token in cookie storage.
我已经读过 JWT 保护网站免受 CSRF 的影响。但是,我无法想象假设我将 JWT 令牌保存在 cookie 存储中会如何工作。
How would it then protect from CSRF?
那么它将如何保护免受 CSRF 的影响?
Update 1
I saw some usage samples like the following:
更新 1
我看到了一些使用示例,如下所示:
curl -v -X POST -H "Authorization: Basic VE01enNFem9FZG9NRERjVEJjbXRBcWJGdTBFYTpYUU9URExINlBBOHJvUHJfSktrTHhUSTNseGNh"
How can I implement that when I make a request to server from the browser? I also saw that some implement the token in the URL:
当我从浏览器向服务器发出请求时,如何实现?我还看到有些人在 URL 中实现了令牌:
http://exmple.com?jwt=token
If I would make a request via AJAX then I could set an header like jwt: [token]and then I could read the token from header.
如果我通过 AJAX 发出请求,那么我可以设置一个标头jwt: [token],然后我可以从标头读取令牌。
Update 2
更新 2
I installed the Advanced REST Client Google Chrome extension and was able to pass the token as a custom header. Is it possible to set this header data via Javascript when making a GET request to the server?
我安装了 Advanced REST Client Google Chrome 扩展程序,并且能够将令牌作为自定义标头传递。向服务器发出 GET 请求时,是否可以通过 Javascript 设置此标头数据?
采纳答案by Florent Morselli
[EDIT] This answer is the accepted one, however the response from Jo?o Angelo is way more detailed and should be considered. One remark though and because the security pratices evolved since Nov. 2016, the Option 2 should be implemented in favour of the Option 1.
[编辑] 这个答案是公认的,但是 Jo?o Angelo 的回复更详细,应该考虑。有一点需要注意,并且由于自 2016 年 11 月以来安全实践发生了变化,因此应实施选项 2 以支持选项 1。
Look at this web site: https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
看这个网站:https: //auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
If you want to store them, you should use the localStorage or sessionStorage if available or cookies. You should also use the Authorization header, but instead of Basic scheme, use the Bearer one:
如果您想存储它们,您应该使用 localStorage 或 sessionStorage(如果可用)或 cookie。您还应该使用 Authorization 标头,但不要使用 Basic 方案,而是使用 Bearer 一:
curl -v -X POST -H "Authorization: Bearer YOUR_JWT_HERE"
With JS, you could use the following code:
使用 JS,您可以使用以下代码:
<script type='text/javascript'>
// define vars
var url = 'https://...';
// ajax call
$.ajax({
url: url,
dataType : 'jsonp',
beforeSend : function(xhr) {
// set header if JWT is set
if ($window.sessionStorage.token) {
xhr.setRequestHeader("Authorization", "Bearer " + $window.sessionStorage.token);
}
},
error : function() {
// error handler
},
success: function(data) {
// success handler
}
});
</script>
回答by Jo?o Angelo
Choosing the storage is more about trade-offs than trying to find a definitive best choice. Let's go through a few options:
选择存储更多的是权衡,而不是试图找到明确的最佳选择。让我们来看看几个选项:
Option 1 - Web Storage (localStorageor sessionStorage)
选项 1 - 网络存储(localStorage或sessionStorage)
Pros
优点
- The browser will not automatically include anything from Web storage into HTTP requests making it notvulnerable to CSRF
- Can only be accessed by Javascript running in the exact same domain that created the data
- Allows to use the most semantically correct approach to pass token authentication credentials in HTTP (the
Authorizationheader with aBearerscheme) - It's very easy to cherry pick the requests that should contain authentication
- 浏览器不会自动将 Web 存储中的任何内容包含到 HTTP 请求中,使其不易受到 CSRF 的攻击
- 只能由在创建数据的完全相同域中运行的 Javascript 访问
- 允许使用语义最正确的方法在 HTTP(
Authorization带有Bearer方案的标头)中传递令牌身份验证凭据 - 挑选应该包含身份验证的请求非常容易
Cons
缺点
- Cannot be accessed by Javascript running in a sub-domain of the one that created the data (a value written by
example.comcannot be read bysub.example.com) - ?? Is vulnerable to XSS
- In order to perform authenticated requests you can only use browser/library API's that allow for you to customize the request (pass the token in the
Authorizationheader)
- 无法被在创建数据的子域中运行的 Javascript 访问(写入的值
example.com不能被读取sub.example.com) - ?? 易受 XSS 攻击
- 为了执行经过身份验证的请求,您只能使用允许您自定义请求的浏览器/库 API(在
Authorization标头中传递令牌)
Usage
用法
You leverage the browser localStorageor sessionStorageAPI to store and then retrieve the token when performing requests.
在执行请求时,您可以利用浏览器localStorage或sessionStorageAPI 来存储和检索令牌。
localStorage.setItem('token', 'asY-x34SfYPk'); // write
console.log(localStorage.getItem('token')); // read
Option 2 - HTTP-only cookie
选项 2 - 仅 HTTP cookie
Pros
优点
- It's notvulnerable to XSS
- The browser automatically includes the token in any request that meets the cookie specification (domain, path and lifetime)
- The cookie can be created at a top-level domain and used in requests performed by sub-domains
- 这是不容易受到XSS
- 浏览器会自动在任何符合 cookie 规范(域、路径和生存期)的请求中包含令牌
- cookie 可以在顶级域中创建并在子域执行的请求中使用
Cons
缺点
- ?? It's vulnerable to CSRF
- You need to be aware and always consider the possible usage of the cookies in sub-domains
- Cherry picking the requests that should include the cookie is doable but messier
- You may (still) hit some issues with small differences in how browsers deal with cookies
- ?? If you're not careful you may implement a CSRF mitigation strategy that is vulnerable to XSS
- The server-side needs to validate a cookie for authentication instead of the more appropriate
Authorizationheader
- ?? 它容易受到 CSRF 的影响
- 您需要注意并始终考虑子域中 cookie 的可能用途
- Cherry 选择应该包含 cookie 的请求是可行的,但更麻烦
- 您可能(仍然)遇到一些问题,浏览器处理 cookie 的方式略有不同
- ?? 如果您不小心,您可能会实施易受 XSS 攻击的 CSRF 缓解策略
- 服务器端需要验证 cookie 进行身份验证,而不是更合适的
Authorization标头
Usage
用法
You don't need to do anything client-side as the browser will automatically take care of things for you.
您不需要在客户端做任何事情,因为浏览器会自动为您处理事情。
Option 3 - Javascript accessible cookie ignored by server-side
选项 3 -服务器端忽略Javascript 可访问 cookie
Pros
优点
- It's notvulnerable to CSRF (because it's ignored by the server)
- The cookie can be created at a top-level domain and used in requests performed by sub-domains
- Allows to use the most semantically correct approach to pass token authentication credentials in HTTP (the
Authorizationheader with aBearerscheme) - It's somewhat easy to cherry pick the requests that should contain authentication
- 它不容易受到 CSRF 的影响(因为它被服务器忽略了)
- cookie 可以在顶级域中创建并在子域执行的请求中使用
- 允许使用语义最正确的方法在 HTTP(
Authorization带有Bearer方案的标头)中传递令牌身份验证凭据 - 挑选应该包含身份验证的请求有点容易
Cons
缺点
- ?? It's vulnerable to XSS
- If you're not careful with the path where you set the cookie then the cookie is included automatically by the browser in requests which will add unnecessary overhead
- In order to perform authenticated requests you can only use browser/library API's that allow for you to customize the request (pass the token in the
Authorizationheader)
- ?? 它容易受到 XSS 攻击
- 如果您不小心设置 cookie 的路径,那么浏览器会自动将 cookie 包含在请求中,这将增加不必要的开销
- 为了执行经过身份验证的请求,您只能使用允许您自定义请求的浏览器/库 API(在
Authorization标头中传递令牌)
Usage
用法
You leverage the browser document.cookieAPI to store and then retrieve the token when performing requests. This API is not as fine-grained as the Web storage (you get all the cookies) so you need extra work to parse the information you need.
document.cookie在执行请求时,您可以利用浏览器API 来存储和检索令牌。此 API 不像 Web 存储(您获得所有 cookie)那样细粒度,因此您需要额外的工作来解析您需要的信息。
document.cookie = "token=asY-x34SfYPk"; // write
console.log(document.cookie); // read
Additional Notes
补充说明
This may seem a weird option, but it does has the nice benefit that you can have storage available to a top-level domain and all sub-domains which is something Web storage won't give you. However, it's more complex to implement.
这似乎是一个奇怪的选择,但它确实有一个很好的好处,即您可以将存储提供给顶级域和所有子域,这是 Web 存储无法提供的。但是,它的实现更加复杂。
Conclusion - Final Notes
结论 - 最后的笔记
My recommendation for most common scenarios would be to go with Option 1, mostly because:
我对最常见场景的建议是使用 Option 1,主要是因为:
- If you create a Web application you need to deal with XSS; always, independently of where you store your tokens
- If you don't use cookie-based authentication CSRF should not even pop up on your radar so it's one less thing to worry about
- 如果您创建一个 Web 应用程序,您需要处理 XSS;始终,独立于您存储令牌的位置
- 如果您不使用基于 cookie 的身份验证 CSRF 甚至不应该出现在您的雷达上,因此无需担心
Also note that the cookie based options are also quite different, for Option 3 cookies are used purely as a storage mechanism so it's almost as if it was an implementation detail of the client-side. However, Option 2 means a more traditional way of dealing with authentication; for a further read on this cookies vs token thing you may find this article interesting: Cookies vs Tokens: The Definitive Guide.
另请注意,基于 cookie 的选项也有很大不同,因为选项 3 cookie 纯粹用作存储机制,因此它几乎就像是客户端的实现细节。然而,选项 2 意味着更传统的处理身份验证的方式;要进一步阅读 cookie 与令牌的相关内容,您可能会发现这篇文章很有趣:Cookie 与令牌:权威指南。
Finally, none of the options mention it, but use of HTTPS is mandatory of course, which would mean cookies should be created appropriately to take that in consideration.
最后,没有一个选项提到它,但使用 HTTPS 当然是强制性的,这意味着应该适当地创建 cookie 以考虑到这一点。
回答by Carlos Arrastia
This blog post has excellent side by side comparison of browser storage vs. cookies and tackles every potential attack in each case. https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/
这篇博文对浏览器存储与 cookie 进行了很好的并排比较,并解决了每种情况下的所有潜在攻击。https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/
The shorter answer / spoiler: cookies and add xsrf token in the jwt. Detailed explanation in the blog post.
简短的答案/剧透:cookies 并在 jwt.js 中添加 xsrf 令牌。博文中有详细解释。
回答by T. Dayya
You should NEVER, EVERstore a JWT outside of memory.
你应该永远,永远不要在内存之外存储 JWT。
If you want to persist a JWT for the duration of a long session (say 1 hour when a token has an expiry of only 15 mins), silently log the users again in the background whenever the token is about to be expired.
如果您想在长时间会话期间保留 JWT(比如 1 小时,当令牌仅到期 15 分钟时),请在令牌即将到期时再次在后台静默记录用户。
If you want to persist a JWT across sessions, you should use a refresh token. Which, BTW, is most of the time used for above purpose as well. You should store it in an HttpOnly cookie (well, more precisely, a sever sets is via Set-Cookie header, the front end calls the /refresh_token API endpoint.)
如果要跨会话保留 JWT,则应使用刷新令牌。顺便说一句,其中大部分时间也用于上述目的。您应该将其存储在 HttpOnly cookie 中(好吧,更准确地说,服务器集是通过 Set-Cookie 标头,前端调用 /refresh_token API 端点。)
A refresh token, BTW, is the least of the evils; to complement it, you should ensure you are following best practices to mitigate XSS.
顺便说一句,刷新令牌是最不坏的;为了补充它,您应该确保遵循最佳实践来缓解 XSS。
localStorage, sessionStorage, and cookies all have their vulnerabilities.
localStorage、sessionStorage 和 cookie 都有其漏洞。
This is the best guide i have ever read on JWTs: https://blog.hasura.io/best-practices-of-using-jwt-with-graphql/
这是我读过的关于 JWT 的最佳指南:https://blog.hasura.io/best-practices-of-using-jwt-with-graphql/

