实现 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 中获取该值。
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.
刚刚了解了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 中获取该值。
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.