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

Tim*_*ce7 142 security authentication cookies csrf jwt

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

最近,我发现JSON Web Token(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. 此外,我发现还有一个博客节目使用"授权标题"和"承载"来发送JWT.我不明白博客谈论的方法.有人可以解释一下"授权标题"和"持票人"的更多信息吗?这是否使所有请求的HTTP头传输JWT?如果是的话,CSRF怎么样?

Ima*_*ghi 129

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

但有几种方法可以确保JWT在cookie中不被轻易窃取(但仍有一些先进技术可以窃取它们).但是,如果您想依赖LocalStorage/SessionStorage,那么可以通过简单的XSS攻击来访问它.

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

双提交Cookie方法

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

  2. 大多数CSRF攻击在其请求中与原始主机具有不同的来源或引用标头.因此,检查标题中是否有任何标题,是否来自您的域名!如果不拒绝他们.如果请求中没有origin和referrer,那么不用担心.您可以依赖X-XSRF-TOKEN标头验证结果,我将在下一步中解释.

  3. 虽然浏览器会自动为请求域提供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 $http服务都会自动执行以下操作:

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

因此,客户端实现将自动为您处理!我们只需要设置一个XSRF-TOKEN在服务器端当前域上命名的cookie ,当我们的API从客户端获得任何调用时,它必须检查X-XSRF-TOKEN头并将其与XSRF-TOKENJWT中的头进行比较.如果它们匹配,则用户是真实的.否则,它是伪造的请求,您可以忽略它.此方法的灵感来自"Double Submit Cookie"方法.

警告

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

无论是将JWT存储在您的存储中localStorage还是将XSRF令牌存储在非HttpOnly cookie中,都可以通过XSS轻松获取.甚至你的HttpOnly cookie中的JWT也可以通过XST方法等高级XSS攻击来获取.

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

在这里阅读更多:

  • 正如您所提到的,如果网站容易受到XSS攻击,那么用户被利用只是时间问题.看起来我们正在为安全性的极小增加而交易显着的复杂性. (5认同)
  • @shusson您必须注意XSS和XSRF攻击,以保护您的JWT。我不同意您为了提高很小的安全性而付出了巨大的复杂性。如果安全很重要,那么您需要尽一切努力避免XSS漏洞。此方法旨在保护您的令牌免受XSRF攻击。但这并不意味着您可以忽略XSS漏洞。 (3认同)
  • @ImanSedighi我不清楚,通过将jwt存储在cookie中,你增加了复杂性,你现在必须防止XSRF.那么为什么不使用具有短生命令牌的本地存储并专注于防止XSS? (3认同)
  • @AranDehkharghani 是的,我想它可以防止重播攻击,特别是如果您更改 JWT 并在每次 API 使用之前的 JWT 时使其过期。这意味着您的 JWT 将变得像一次性密码 (OTP)。您可以通过不同的方式使用 JWT,具体取决于您对平台安全性的关心程度。 (2认同)
  • @Royi Namir:如果您使用10美元的SSL证书,Wireshark欺骗不应该是一个问题!如果网站的安全性很重要,那么您应该加密数据并使用HTTPS协议. (2认同)

Mvd*_*vdD 64

JWT令牌很受欢迎,因为它们在新的授权和身份验证协议(如OAuth 2.0OpenID Connect)中用作默认令牌格式.

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

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

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

  • 这是否意味着我们可以有效地将jwt存储在cookie中,如果我们在Authorization标头中发送请求,它将是安全的吗? (12认同)
  • @cameronjroe您可以将它存储在您的cookie中,但前提是您不使用您的cookie进行身份验证(在这种情况下您使用标题) (8认同)
  • @MvdD 我不清楚如何/在哪里存储令牌以便能够访问它以在承载身份验证标头中发送。如果可以通过 javascript 从 cookie 中读取它,那么它就很容易受到 XSS 攻击。本地存储同样容易受到 XSS 攻击。正如 iman-sedighi 在他的帖子中提到的那样,使用 X-XSRF-TOKEN 标头进行 Cookie 身份验证听起来更安全(当然还有其他 XSS 保护和禁用 TRACE 请求等) (6认同)
  • 我是说如果您的API仅从Authorization标头中检索JWT令牌,则它不容易受到CSRF的攻击.从cookie获取令牌的任何站点或API都需要CSRF缓解. (4认同)
  • AJAX 调用也源自浏览器。JWT 令牌主要用于验证 Web API(提供数据),而 Cookie 则用于验证 Web 应用程序(提供标记、图像、CSS 和 JavaScript) (2认同)

Big*_*kin 33

现在在 2020 年,只需将 JWT 令牌存储在 cookie 中SameSite=strict即可击败 CSRF。当然,保持securehttpOnly太。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite

  • 此方法的唯一问题是,您无法在 Safari 14+ 中使用它,并且在 2022 年当您需要 Web 小部件的跨站点 Cookie 时,也将无法在 Chrome 中使用它。 (3认同)
  • @trademark 如果您开发像 Intercom 这样的第 3 方应用程序,简单的“httpOnly”cookie 根本不起作用。因为您的应用程序希望在页面刷新时保持客户端网站中的访问者会话。由于 cookie 无法存储在您的服务器中,因此它不再是解决方案(https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/)。 (2认同)

Asp*_*ian 24

将您的访问令牌存储在内存中并将刷新令牌存储在 cookie 中

为什么这对 CSRF 是安全的?

尽管提交的表单/refresh_token将起作用并且将返回新的访问令牌,但如果攻击者使用 HTML 表单,则他们无法读取响应。为了防止攻击者成功发出 fetch 或 AJAX 请求并读取响应,这需要正确设置授权服务器的 CORS 策略以阻止来自未经授权的网站的请求。

你可以在这里读更多关于它的内容:

https://dev.to/cotter/localstorage-vs-cookies-all-you-need-to-know-about-storing-jwt-tokens-securely-in-the-front-end-15id


小智 16

在网络浏览器中,您可以将 JWT 存储在本地/会话存储cookie中。两者都有漏洞。您可以选择您喜欢的一种,但您应该将安全性作为一个整体来保障,并且流程应该设计良好。如果你只预防 XSRF 和 XSS,那对你没有帮助。这是对你的问题的简短回答。

首先您要防止用户数据被盗。非常有问题的是XSS攻击。如果您使用存储,攻击者可以窃取令牌 - 将令牌发送到他的服务器并发出请求来窃取用户数据。如果您使用httpOnly cookie,他无法窃取令牌,但他可以发送请求(浏览器包含cookie,如果脚本位于同一域),读取响应并将用户数据发送到他的服务器。结果是一样的。

为了防止将数据发送到具有不同域的服务器,您可以使用Content-Security-Policy标头。我建议研究所有安全标头和网络安全。OWASP 是很好的资源。这个论坛不是为了写很多页面。

XSRF(CSRF)

如果您使用cookie,那么应用程序很容易受到这种攻击。

如何预防:

设置 httpOnly、secured 和 SameSite=strict 标志。您还可以在不使用 httpOnly 的情况下使用第二个 Cookie XSRF-TOKEN,并将其值与此 Cookie 一起在标头 X-Xsrf-Token 中发送。但如果浏览器支持的话,可以通过 SameSite 标志解决这个问题。

跨站脚本攻击

从某种意义上说,存储和 cookie 都容易受到 XSS 攻击。使用 javascript 代码,您可以读取存储,并且可以使用浏览器包含的 cookie 向服务器发送请求,因为您位于同一域中。如果您使用用户输入,您应该转义/清理它们。您还可以使用标头 x-xss-protection。最有问题的是第三方 js 库中的恶意代码,因为您无法逃脱它并且它在同一域上运行。您可以防止用户数据因您的错误而被窃取,但此类代码可能会给您的应用程序和用户带来不同的问题。


big*_*ann 8

存储 JWT 的整个问题的另一个角度:

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

签出这个动机

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

最安全的选项是in-memory结帐这个深入潜水

  • 这个答案需要加载更多信息,**为什么**在内存中更“安全”**为什么**其他选项不“安全”。事实上,不存在“安全”存储。因此,如果您要大胆主张人们不应该做什么,您需要提供事实来支持这些主张。不,网页链接不算在内。 (4认同)
  • 内存中仍然容易受到 XSS 的影响,不是吗?如果是这样,那么受 CSRF 保护的 cookie 似乎是唯一安全的解决方案。 (2认同)