Where to store JWT in browser? How to protect against CSRF?
我知道基于cookie的身份验证。可以应用SSL和HttpOnly标志来保护来自MITM和XSS的基于cookie的身份验证。但是,需要采取更多特殊措施以保护其免受CSRF的影响。它们有点复杂。 (参考)
最近,我发现JSON Web Token(JWT)作为身份验证的解决方案非常热门。我知道有关编码,解码和验证JWT的内容。但是,我不明白为什么有些网站/教程在使用JWT时不需要CSRF保护。我已经阅读了很多,并试图总结下面的问题。我只是希望有人可以提供JWT的全貌并澄清我对JWT误解的概念。
如果JWT存储在cookie中,我认为它与基于cookie的身份验证相同,只是服务器不需要有会话来验证cookie /令牌。如果没有实施特殊措施,CSRF仍存在风险。 JWT不是存储在cookie中吗?
如果JWT存储在localStorage / sessionStorage中,那么没有cookie所以不需要防止CRSF。问题是如何将JWT发送到服务器。我发现这里建议使用jQuery通过ajax请求的HTTP头发送JWT。那么,只有ajax请求才能进行身份验证吗?
此外,我发现还有一个博客节目使用"授权标题"和"承载"来发送JWT。我不明白博客谈论的方法。有人可以解释一下"授权标题"和"持票人"的更多信息吗?这是否使所有请求的HTTP头传输JWT?如果是的话,CSRF怎么样?
我们需要将JWT存储在客户端计算机上。如果我们将它存储在LocalStorage / SessionStorage中,那么它很容易被XSS攻击抓取。如果我们将其存储在cookie中,那么黑客可以在CSRF攻击中使用它(不读取它)并冒充用户并联系我们的API并发送请求以执行操作或代表用户获取信息。
但有几种方法可以确保JWT在cookie中不被轻易窃取(但仍有一些先进技术可以窃取它们)。但是,如果您想依赖LocalStorage / SessionStorage,那么可以通过简单的XSS攻击来访问它。
因此,为了解决CSRF问题,我在我的应用程序中使用Double Submit Cookies。
双提交Cookie方法
将JWT存储在HttpOnly cookie中,并在安全模式下使用它通过HTTPS传输。
大多数CSRF攻击在其请求中与原始主机具有不同的来源或引用标头。因此,检查标题中是否有任何标题,是否来自您的域名!如果不拒绝他们。如果请求中没有origin和referrer,那么不用担心。您可以依赖X-XSRF-TOKEN标头验证结果,我将在下一步中解释。
虽然浏览器会自动为请求域提供Cookie,但有一个有用的限制:网站上运行的JavaScript代码无法读取其他网站的Cookie。我们可以利用它来创建我们的CSRF解决方案。为了防止CSRF攻击,我们必须创建一个额外的Javascript可读cookie,称为:XSRF-TOKEN。必须在用户登录时创建此cookie,并且该cookie应包含随机的,不可猜测的字符串。我们还将这个号码保存在JWT本身作为私人索赔。每次JavaScript应用程序想要发出请求时,都需要读取此令牌并将其发送到自定义HTTP标头中。因为这些操作(读取cookie,设置标题)只能在JavaScript应用程序的同一个域上完成,所以我们可以知道这是由使用我们的JavaScript应用程序的真实用户完成的。
Angular JS让您的生活更轻松
幸运的是,我在我们的平台中使用Angular JS,而Angular包装了CSRF令牌方法,使我们更容易实现。对于我们的Angular应用程序对服务器的每个请求,Angular
- 在当前域中查找名为XSRF-TOKEN的cookie。
- 如果找到该cookie,它将读取该值并将其作为X-XSRF-TOKEN标头添加到请求中。
因此,客户端实现将自动为您处理!我们只需要在服务器端的当前域上设置一个名为
警告
实际上,您仍然容易受到XSS的攻击,只是攻击者无法窃取您的JWT令牌供以后使用,但他仍然可以使用XSS代表您的用户发出请求。
无论是将JWT存储在
因此,除了Double Submit Cookies方法之外,您还必须始终遵循针对XSS的最佳实践,包括转义内容。这意味着删除任何可能导致浏览器执行您不??希望的操作的可执行代码。通常,这意味着删除导致JavaScript被评估的
在这里阅读更多:
- Angular的XSRF:它是如何工作的
- 存储JWT的位置 - Cookies与HTML5 Web存储
-
感谢您提供超详细的回复。如果我将jwt存储在一个httpOnly cookie中,并将jwt的签名作为CSRF令牌存储在另一个cookie中,这是一个好主意 -
X-XSRF-TOKEN ,这是由Angular自动使用的?在CSRF令牌中使用签名的原因是它可以很容易地验证 - @ShadyKiller是的,这种方式也是Double Submit Cookies Method的一个例子。您可以将JWT的签名存储在X-XSRF-TOKEN中以获得角度。由于只读取cookie和设置标题只能在JavaScript应用程序的同一个域上完成,因此您可以安全地使用CSRF。但是,您必须验证服务器端的签名,以确保JWT和您签发的签名(以及您的密钥)。
- 嗨,Iman,感谢您的回复,这个XSRF-TOKEN设置是否也可以防止重放攻击?对我来说这是因为攻击者无法重放消息,因为他们无法模仿xsrf-token,如果是这样,为什么JID专门用于重放攻击预防?
- @AranDehkharghani是的,我想它可以防止重放攻击,特别是如果你改变JWT并且每次API使用它都会使之前的JWT失效。这意味着你的JWT将变成一次性密码(OTP)。您可以通过不同方式使用JWT,具体取决于您对平台安全性的关注程度。
- @ImanSedighi感谢您的回复,如果我实现OTP,那么它意味着我只能将它用于一个进一步的请求,现在可能是解决方案,如果我需要从javascript发送并发请求,可能会返回一个JWT池到客户端请求收到?听起来不是很优雅
- 正如您所提到的,如果网站容易受到XSS攻击,那么用户被利用只是时间问题。看起来我们正在为安全性的极小增加而交易显着的复杂性。
- @shusson您必须处理XSS和XSRF攻击以保护您的JWT。我不同意您为安全性的极小增加而交易显着的复杂性。如果安全性很重要,那么您需要尽一切努力不要有XSS漏洞。此方法旨在保护您的令牌免受XSRF攻击。但这并不意味着您可以忽略XSS漏洞。
- @ImanSedighi我不清楚,通过将jwt存储在cookie中,你增加了复杂性,你现在必须防止XSRF。那么为什么不使用具有短生命令牌的本地存储并专注于防止XSS?
- 使用xsrf-token有一个缺点,你必须将它作为X-XSRF-TOKEN标头发送,只有你可以用JS读取cookie才能添加标头,只有当它不是HTTP时才可以用JS读取cookie cookie,如果是HTTP cookie,则不能进行CORS,因此您的应用必须位于同一个域中。你找到了解决方案吗?这就是我从REST api中删除csrf保护的原因。
- OWASP是网络漏洞的最佳办法owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
- @ImanSedighi如果我们只是将JWT存储在cookie中,并且要求所有XHR请求通过使用Javascript从cookie读取而将JWT包含在授权头中,并将服务器更改为从头部读取(INSTEAD OF THE曲奇饼)。存储在cookie中本质上保护我们不受XSS的影响,并且为了消除CSRF,我们使用自己的JS代码读取cookie并将JWT附加到头部。我不知道XSRF-TOKEN必须在哪里发挥作用,但我打赌我错过了......
- ^当我说cookie本质上保护我们免受XSS攻击时,我错过了一个关键点。重要的是,cookie仅限HTTP,因为它对XSS是安全的。所以忽略我上面所说的。
- @ImanSedighi再想一想,你建议的双提交方法是不是容易受到XSS后跟CSRF的影响?为了清楚起见,黑客可以使用XSS来检索不仅仅是HTTP的XSRF-TOKEN cookie,然后他可以在他的网站上使用CSRF将带有XSRF-TOKEN的AJAX请求作为易受攻击主机的标头之一发送。在这种情况下,当脆弱主机的域与cookie域匹配时,cookie也将被发送。你是什??么意思"只是攻击者不能偷你[J] JWT令牌供以后使用"?为什么不?
- 我完全不同意。使用代理wireshark很容易欺骗原始标头。减轻CSRF的正确方法是使用另一个未知(!!!!!!!!!)值(对攻击者),这类似于最初发送到表单的GUID输入。 (隐藏的领域。
- @LeoLei此解决方案用于防止CSRF攻击。正如我在警告部分中提到的,您也应该在代码中处理XSS攻击。但是如果你仔细编码,逃避一切并在服务器端使用一个好的框架,那么防止XSS攻击就不那么难了。正如我所说,你必须始终遵循针对XSS的最佳实践。
- @Royi Namir:如果您使用10美元的SSL证书,Wireshark欺骗不应该是一个问题!如果网站的安全性很重要,那么您应该加密数据并使用HTTPS协议。
- @BigDong看,我们在这里谈论两个cookie。 1- JWT cookie,应保存在仅HTTP的cookie中。 2- XSRF-TOKEN cookie,它不是仅HTTP的cookie。 因此,如果您以这种方式存储令牌,那么您将不会遇到任何CORS问题。 因为您的浏览器可以访问XSRF-TOKEN值,并且您的js或Angular JS代码可以获取令牌的值并将其作为X-XSRF-TOKEN标头发送给服务器。
- @ImanSedighi:你怎么能这种提交表单的方法 - 我没有使用任何框架。 如何在提交表单时修改请求标头/
- @ j10没有任何框架,您将表单中的CSRF-Token呈现为隐藏字段而不是标题。 当然,您必须在JWT或用户会话中将此字段与CSRF-Token进行比较。
JWT令牌很受欢迎,因为它们在新的授权和身份验证协议(如OAuth 2.0和OpenID Connect)中用作默认令牌格式。
当令牌存储在cookie中时,浏览器会自动将其与每个请求一起发送到同一域,这仍然容易受到CSRF攻击。
承载认证是HTTP中定义的认证方案之一。 它基本上意味着
承载方案通常用于保护通过AJAX调用或移动客户端使用的Web API(REST服务)。
- 那么进行Bearer身份验证的唯一方法是通过ajax请求吗?
- @Timespace7不,JWT令牌也经常在本机客户端使用。 OAuth 2.0具有专门针对本机(移动)客户端的流程。他们不做的是隐式浏览器身份验证(如cookie或基本身份验证)。
- 让我总结一下,你说: - 如果我们将JWT发送给我们的用户,我们将其保存在cookie中,然后每当我们调用api手动添加Authoritzation标头时,我们都可以防止CSRF攻击?
- 我是说如果您的API仅从Authorization标头中检索JWT令牌,则它不容易受到CSRF的攻击。从cookie获取令牌的任何站点或API都需要CSRF缓解。
- 这是否意味着我们可以有效地将jwt存储在cookie中,如果我们在Authorization标头中发送请求,它将是安全的吗?
- @cameronjroe你可以将它存储在你的cookie中,但前提是你不使用你的cookie进行身份验证(在这种情况下你使用你的标题)
-
@MvdD正??如你所说,JWT不适合保护网站,因为浏览器不会自动发送它。这是否意味着JWT不适用于
authenticating requests originated from a browser ?如果所有请求都以ajax 发出,这意味着我的JS将always 显式发送令牌,而不是依赖浏览器隐式发送cookie。 - AJAX调用也来自浏览器。 JWT令牌主要用于验证Web API(服务数据)与用于验证Web应用程序的cookie(服务标记,图像,CSS和JavaScript)
- 我还想知道如何在客户端与我的网络应用程序的html文档一起进行身份验证后立即将jwt令牌发送到客户端而不使用cookie。但直到现在,我还是无法找到一种自然的感觉,简单的方法。有办法吗?我在这里问过:stackoverflow.com/questions/34837751/
- 存储在cookie中的任何令牌都容易受到CSRF攻击,无论您是通过身份验证头发送它,另一方面如果您在请求头中发送令牌而不使用cookie,您可能会受到XSS攻击(跨站点脚本)这意味着黑客编写的javascript代码可以在您的域上运行(在客户端)并且代码的安静可以窃取令牌并使用它,我发现这篇文章很有用:链接
- @MvdD我不清楚如何/在哪里存储令牌以便能够访问它以在Bearer身份验证标头中发送。如果可以通过javascript从cookie中读取它,那么它很容易受到XSS的攻击。本地存储同样容易受到XSS的攻击。带有X-XSRF-TOKEN标头的Cookie身份验证,因为iman-sedighi在帖子中提到听起来更安全(当然还有其他XSS保护和禁用TRACE请求等)