在基于浏览器的应用程序中保存JWT的位置以及如何使用它

时间:2014-10-13 12:41:49

标签: javascript web-services security cookies jwt

我试图在我的身份验证系统中实现JWT,我有几个问题。要存储令牌,我可以使用Cookie,但也可以使用localStoragesessionStorage

哪个是最佳选择?

我已经读过JWT保护网站免受CSRF的侵害。但是,我无法想象假设我将JWT令牌保存在cookie存储中会如何工作。

那么它如何防止CSRF?

更新1
我看到了一些使用示例,如下所示:

curl -v -X POST -H "Authorization: Basic VE01enNFem9FZG9NRERjVEJjbXRBcWJGdTBFYTpYUU9URExINlBBOHJvUHJfSktrTHhUSTNseGNh"

当我从浏览器向服务器发出请求时,如何实现?我还看到有些人在URL中实现了令牌:

http://exmple.com?jwt=token

如果我通过AJAX发出请求,那么我可以设置一个像jwt: [token]的标题然后我可以从标题中读取标记。

更新2

我安装了高级REST客户端Google Chrome扩展程序,并且能够将令牌作为自定义标头传递。在向服务器发出GET请求时,是否可以通过Javascript设置此标头数据?

5 个答案:

答案 0 :(得分:80)

选择存储更多的是权衡,而不是试图找到明确的最佳选择。我们来看几个选项:

选项1 - 网络存储(localStoragesessionStorage

赞成

  • 浏览器不会自动将任何内容从Web存储包含到HTTP请求中,使其容易受到CSRF攻击
  • 只能通过在创建数据的完全相同的域中运行的Javascript访问
  • 允许使用最具语义正确的方法在HTTP中传递令牌身份验证凭据(带Authorization方案的Bearer标头)
  • 很容易选择应包含身份验证的请求

缺点

  • 无法通过在创建数据的子域中运行的Javascript访问(example.com无法读取sub.example.com写的值)
  • ⚠️易受XSS攻击
  • 为了执行经过身份验证的请求,您只能使用允许自定义请求的浏览器/库API(在Authorization标头中传递令牌)

用法

您可以利用浏览器localStoragesessionStorage API来存储,然后在执行请求时检索令牌。

localStorage.setItem('token', 'asY-x34SfYPk'); // write
console.log(localStorage.getItem('token')); // read

选项2 - 仅HTTP的cookie

赞成

  • 易受XSS
  • 攻击
  • 浏览器会自动在符合Cookie规范(域,路径和生命周期)的任何请求中包含令牌
  • 可以在顶级域创建cookie,并将其用于子域执行的请求

缺点

  • ⚠️它容易受到CSRF的影响
  • 您需要了解并始终考虑在子域中使用Cookie的可能性
  • Cherry选择应该包含cookie的请求是可行的但是更加混乱
  • 您可能(仍然)遇到一些与浏览器处理Cookie的方式存在细微差别的问题
  • ⚠️如果您不小心,可以实施易受XSS攻击的CSRF缓解策略
  • 服务器端需要验证cookie以进行身份​​验证,而不是更合适的Authorization标头

用法

您无需在客户端执行任何操作,因为浏览器会自动为您处理事情。

选项3 - 服务器端忽略的Javascript访问cookie

赞成

  • 容易受到CSRF攻击(因为服务器忽略了
  • 可以在顶级域创建cookie,并将其用于子域执行的请求
  • 允许使用最具语义正确的方法在HTTP中传递令牌身份验证凭据(带Authorization方案的Bearer标头)
  • 选择应包含身份验证的请求
  • 有点容易

缺点

  • ⚠️它易受XSS攻击
  • 如果你不小心设置cookie的路径,那么浏览器会在请求中自动包含cookie,这会增加不必要的开销
  • 为了执行经过身份验证的请求,您只能使用允许自定义请求的浏览器/库API(在Authorization标头中传递令牌)

用法

您可以利用浏览器document.cookie API在执行请求时存储然后检索令牌。此API不像Web存储那样精细(您获得所有cookie),因此您需要额外的工作来解析所需的信息。

document.cookie = "token=asY-x34SfYPk"; // write
console.log(document.cookie); // read

附加说明

这似乎是一个奇怪的选择,但它确实有一个很好的好处,你可以让存储可用于顶级域和所有子域,这是Web存储不会给你的东西。但是,实施起来更复杂。

结论 - 最终笔记

我对大多数常见情况的建议是选择1 ,主要是因为:

  • 如果您创建Web应用程序,则需要处理XSS;始终,独立于您存储令牌的位置
  • 如果您不使用基于cookie的身份验证,CSRF甚至不应该出现在您的雷达上,因此不用担心这一点

另请注意,基于cookie的选项也大不相同,因为选项3 cookie仅用作存储机制,因此它几乎就像是客户端的实现细节。但是,备选方案2意味着更传统的处理身份验证的方式;有关此cookie与令牌的进一步阅读,您可能会发现这篇文章很有趣:Cookies vs Tokens: The Definitive Guide

最后,没有一个选项提到它,但当然必须使用HTTPS,这意味着应该适当地创建cookie以考虑到这一点。

答案 1 :(得分:22)

请看这个网站:https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/

如果要存储它们,则应使用localStorage或sessionStorage(如果可用)或cookie。 您还应该使用Authorization标头,但不使用Basic方案,而是使用Bearer one:

curl -v -X POST -H "Authorization: Bearer YOUR_JWT_HERE"

使用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>

答案 2 :(得分:9)

此博客文章对浏览器存储与Cookie进行了良好的并排比较,并解决了每种情况下的每次潜在攻击。 https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/

较短的答案/剧透:cookies并在jwt中添加xsrf标记。博客文章中的详细解释。

答案 3 :(得分:4)

截至 2021 年,随着在当今大多数浏览器上为 cookie 引入了SameSite:松散/严格选项,事情发生了一些变化 >

所以要详细说明 João Angelo 的回答,我想说现在最安全的方法是:

使用以下选项将 JWT 存储在 cookie 中

  • HttpOnly
  • 安全
  • SameSite:松散或严格

这将同时避免 XSS 和 CSRF

答案 4 :(得分:0)

您应该从不将JWT存储在内存之外。

如果您要在一个较长的会话期间(例如令牌过期仅15分钟,则要保留1个小时)来保留JWT,则每当令牌即将过期时,静静地再次在后台登录用户。

如果要在会话之间持久保留JWT,则应使用刷新令牌。顺便说一句,顺便说一句,大部分时间也用于上述目的。您应该将其存储在HttpOnly cookie中(更确切地说,是通过Set-Cookie标头设置服务器,前端调用/ refresh_token API端点。)

刷新令牌BTW是最少的弊端;作为补充,您应该确保遵循最佳实践来减轻XSS。

localStorage,sessionStorage和cookie都具有漏洞。

这是我在JWT上阅读过的最好的指南: https://blog.hasura.io/best-practices-of-using-jwt-with-graphql/