实现 CSRF 免费 JWT 身份验证的安全方法

Secure ways to implement CSRF free JWT authentification

刚刚了解了JWT认证。将 JWT 令牌存储在 localStorage/sessionStorage 中会暴露给 XSS。将其存储在 cookie 中容易受到 CSRF 的攻击。我一直在研究这个并且我想到了这个解决方案,但我不确定它有多安全以及我是否应该在生产中使用它。

解决方案是从服务器获取 JWT 令牌,将其存储在 cookie 中。生成一个 CSRF 令牌(将存储在 JWT 中),该令牌将与每个 HTML 页面一起发送,可以在隐藏的 HTML 字段中作为全局 JS 变量 ()。该 CSRF 令牌将与使用 JS/AJAX 的每个请求一起发送。这样我们就可以先排除CSRF再验证JWT token

我不确定是应该为每个加载的页面发送一个新令牌,还是应该为每个会话保留一个令牌。第一种情况意味着只有最后加载的 page/form 才能提交(如果用户打开了其他页面的多个选项卡,这可能会出现问题)。

这是可用于生产的安全解决方案吗?

此外,还有哪些其他可行的解决方案可以达到相同的目标?

这是我对这个问题的理解。

  • JWT 令牌 - 存储在 httponly/secure cookie 中 - 这可确保任何 Javascript 无法访问它
  • CSRF 令牌 - 由 JS 存储 - 登录时,将声明附加为 header(包括您的 CSRF 值)

当 JS 获得 header 时,它可以将声明存储在 cookie、本地存储或 session 存储中。因为没有 JS 可以访问 cookie 中的 JWT 令牌,所以通过将 CSRF 附加到每个请求并确保它与 JWT 中的内容相匹配,您可以确保是您的 JS 发送请求并且是您的后端发出了令牌。

隐藏字段不是很好的解决方案,因为您必须将它添加到每个请求中。根据您使用的框架,您应该能够将 CSRF 令牌加载到负责在刷新页面时在每个请求上将令牌作为 header 发送的任何内容。将所有声明保存在本地存储或 cookie 中的好处是您可以保留用户的前端状态。拥有 exp 声明意味着您可以知道用户何时不再在安全 jwt 令牌 cookie 中拥有有效令牌,并且您可以重定向到登录页面。

  • session存储 - 仅特定于选项卡
  • localstorage - 特定于跨选项卡的域
  • cookie - 特定于跨标签的域

将 CSFR 添加到 AJAX 请求:

    $.ajax({
        type:"POST",
        beforeSend: function (request)
        {
            request.setRequestHeader("CSRF-TOKEN", csrfToken);
        },
        url: "entities",
        data: "json=" + escape(JSON.stringify(createRequestObject)),
        processData: false,
        success: function(msg) {
            $("#results").append("The result =" + StringifyPretty(msg));
        }
});

即使您没有使用 Angular,这仍然适用。您应该将令牌作为 header 附加到 JS 中,并且可以从 cookie 中获取该值。

来自Angular JS Documentation

When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript that runs on your domain can read the cookie, your server can be assured that the XHR came from JavaScript running on your domain.