在浏览器中的何处存储JWT?如何防范CSRF?


159

我知道基于cookie的身份验证。SSL和HttpOnly标志可以应用于保护来自MITM和XSS的基于cookie的身份验证。但是,将需要采取更多特殊措施来保护它免受CSRF的侵害。它们只是有点复杂。(参考

最近,我发现JSON Web令牌(JWT)作为身份验证的解决方案非常热门。我知道有关编码,解码和验证JWT的知识。但是,我不明白为什么某些网站/教程告诉您使用JWT不需要CSRF保护。我已经阅读了很多,并尝试总结以下问题。我只希望有人可以提供JWT的概况,并阐明我对JWT误解的概念。

  1. 如果JWT存储在cookie中,则我认为它与基于cookie的身份验证相同,除了服务器不需要会话来验证cookie /令牌。如果不采取特殊措施,CSRF仍有风险。JWT是否存储在cookie中?

  2. 如果JWT存储在localStorage / sessionStorage中,则没有cookie,因此不需要防御CRSF。问题是如何将JWT发送到服务器。我在这里发现建议使用jQuery通过Ajax请求的HTTP标头发送JWT。那么,只有ajax请求可以进行身份​​验证吗?

  3. 此外,我还发现了另一个博客节目,使用“ Authorization标头”和“ Bearer”发送JWT。我不了解博客谈论的方法。有人可以解释一下“授权标头”和“承载者”吗?这是否会使通过所有请求的HTTP标头传输的JWT?如果是,CSRF怎么样?

Answers:


70

JWT令牌之所以受欢迎,是因为它们在OAuth 2.0OpenID Connect等新的授权和身份验证协议中用作默认令牌格式。

当令牌存储在cookie中时,浏览器将自动将其与每个请求一起发送到同一域,这仍然容易受到CSRF攻击。

承载身份验证是HTTP中定义的身份验证方案之一。这基本上意味着YOU将(JWT)令牌粘贴在请求的Authorization HTTP标头中。浏览器将NOT自动为您执行此操作,因此不适合保护您的网站。由于浏览器不会自动将标头添加到您的请求中,因此它不会受到CSRF攻击的影响,CSRF攻击取决于将身份验证信息自动提交到原始域。

承载方案通常用于保护通过AJAX调用或移动客户端使用的Web API(REST服务)。


1
@ Timespace7不,本地客户端也经常使用JWT令牌。OAuth 2.0具有专门针对本机(移动)客户端的流。他们不做的是隐式浏览器身份验证(例如cookie或基本身份验证)。
MvdD

5
我说的是,如果您的API仅从Authorization标头中检索JWT令牌,则CSRF不会受到攻击。从cookie获取令牌的任何站点或API都需要CSRF缓解措施。
MvdD

13
这是否意味着我们可以有效地将jwt存储在cookie中,并且如果我们在Authorization标头中发送带有jwt的请求,它将是安全的?
cameronroe

10
@cameronjroe,您可以将其存储在Cookie中,但前提是不使用Cookie进行身份验证(在这种情况下,您需要使用标头)
Jaakko 2015年

1
AJAX调用也源自浏览器。JWT令牌主要用于对Web API(服务数据)进行身份验证,而Cookie用于对Web应用程序(服务标记,图像,CSS和JavaScript)进行身份验证
MvdD 2015年

143

我们需要将JWT存储在客户端计算机上。如果我们将其存储在LocalStorage / SessionStorage中,那么XSS攻击很容易抓住它。如果我们将其存储在cookie中,则黑客可以在CSRF攻击中使用它(无需阅读)并假冒用户并联系我们的API,并发送代表用户采取行动或获取信息的请求。

但是,有几种方法可以保护cookie中的JWT不易被盗(但仍有一些先进的技术可以窃取它们)。但是,如果您要依赖LocalStorage / SessionStorage,则可以通过简单的XSS攻击对其进行访问。

因此,为了解决CSRF问题,我在应用程序中使用了Double Submit Cookies。

双重提交Cookies方法

  1. 将JWT存储在HttpOnly cookie中,并以安全模式使用它来通过HTTPS进行传输。

  2. 大多数CSRF攻击在其请求中具有与原始主机不同的来源或引荐来源标头。因此,请检查标头中是否包含其中的任何一个,它们是否来自您的域!如果不拒绝他们。如果请求中没有原始来源和引荐来源网址,则无需担心。您可以依靠X-XSRF-TOKEN标头验证结果的结果,我将在下一步中进行解释。

  3. 虽然浏览器将自动为请求的域提供cookie,但存在一个有用的限制:网站上运行的JavaScript代码无法读取其他网站的cookie。我们可以利用它来创建我们的CSRF解决方案。为了防止CSRF攻击,我们必须创建一个额外的Javascript可读cookie,称为:XSRF-TOKEN。该cookie必须在用户登录时创建,并且应包含一个随机的,不可猜测的字符串。我们也将此数字作为私人声明保存在JWT本身中。每当JavaScript应用程序想要发出请求时,它将需要读取此令牌并将其发送到自定义HTTP标头中。由于这些操作(读取Cookie,设置标题)只能在JavaScript应用程序的同一域上进行,

Angular JS使您的生活更轻松

幸运的是,我在平台上使用了Angular JS,并且Angular打包了CSRF令牌方法,这使我们更易于实现。对于我们的Angular应用程序对服务器的每个请求,Angular $http服务将自动执行以下操作:

  • 在当前域中查找名为XSRF-TOKEN的cookie。
  • 如果找到该cookie,它将读取该值并将其作为X-XSRF-TOKEN标头添加到请求中。

这样,客户端实现将自动为您处理!我们只需要XSRF-TOKEN在服务器端的当前域上设置一个名为cookie的cookie ,当我们的API收到来自客户端的任何调用时,它必须检查X-XSRF-TOKEN标头并将其与XSRF-TOKENJWT中的进行比较。如果它们匹配,则用户是真实的。否则,这是伪造的请求,您可以忽略它。此方法受“双重提交Cookie”方法的启发。

警告

实际上,您仍然容易受到XSS的攻击,只是攻击者无法窃取您的JWT令牌供以后使用,但攻击者仍然可以使用XSS代表您的用户发出请求。

无论您将JWT存储在中localStorage还是将XSRF令牌存储在非HttpOnly cookie中,XSS都可以轻松地将它们两者都捕获。即使是HttpOnly cookie中的JWT,也可以通过高级XSS攻击(例如XST方法)来捕获

因此,除了Double Submit Cookies方法外,您还必须始终遵循针对XSS的最佳做法,包括转义内容。这意味着删除所有可能导致浏览器执行您不​​希望执行的操作的可执行代码。通常,这意味着删除// <![CDATA[导致JavaScript评估的标记和HTML属性。

在这里阅读更多:


1
@AranDehkharghani是的,我想它可以防止重播攻击,尤其是当您更改JWT并在API每次使用它时使先前的JWT过期时。这意味着您的JWT将变成一次性密码(OTP)。您可以以不同方式使用JWT取决于您对平台安全性的关注程度。
伊曼·塞迪吉

7
正如您提到的,如果网站容易受到XSS的攻击,那么剥削用户只是时间问题。似乎我们正在以极大的安全性来换取极大的复杂性。
舒森,2016年

3
@shusson您必须注意XSS和XSRF攻击,以保护您的JWT。我不同意您为了提高很小的安全性而付出了巨大的复杂性。如果安全很重要,那么您需要尽一切努力避免XSS漏洞。此方法旨在保护令牌免受XSRF攻击。但这并不意味着您可以忽略XSS漏洞。
伊曼·塞迪吉

5
@ImanSedighi我不清楚,通过将jwt存储在cookie中,您增加了复杂性,现在必须防止XSRF。那么,为什么不只使用带有短寿命令牌的本地存储并专注于防止XSS呢?
舒森,2016年

2
@Royi Namir:如果您使用10美元的SSL证书,则不必担心Wireshark的欺骗!如果网站的安全性很重要,那么您应该加密数据并使用HTTPS协议。
伊曼·塞迪吉

2

整个存储JWT的另一个角度是:

  1. JWT永远不应存储在您的localStorage中
  2. 实际上,除非您能够实施非常严格的CSRF保护否则甚至不应该将它们存储在您的Cookie中

查看此动机

  • JWT作为id_token就像您的用户凭据
  • JWT作为access_token就像您的会话令牌

最安全的选择是内存中查看此内容以进行深入的了解

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.