cookie 是否可以保护令牌免受 XSS 攻击? [英] Do cookies protect tokens against XSS attacks?

查看:31
本文介绍了cookie 是否可以保护令牌免受 XSS 攻击?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为基于浏览器的 Javascript Web 应用程序构建基于 JWT(JSON Web 令牌)的身份验证机制,使用无状态服务器(没有用户会话!),我想一劳永逸地知道,如果使用将我的 JWT 令牌存储在 cookie 中可以保护我的令牌免受 XSS 攻击,或者如果没有保护,那么与在我的 Javascript 应用程序中使用浏览器本地存储相比,没有真正的优势.

我在 SO 和许多博客中看到过这个问题的提问和回答,但我从未见过真正让我满意的答案.


这个问题最初是在征求意见的基础上提出的 - 考虑到我原来的措辞,这是正确的.因此,让我在这里和现在清楚地表明,我不想要基于开发人员懒惰等模糊概念的意见 - 这就是基本规则旨在消除的.我想要的是一个有证据支持的是/否答案.要么:

  • 是的,可以保护 cookie 免受 XSS 和 CSRF 的侵害,方法如下"
  • 不,通过保护您的 cookie 免受 CSRF 的影响,您总是将它们暴露在同一种 XSS 攻击面前,而这种攻击首先使 cookie 成为一个好主意"

所以我将重述这个问题,使用一些简化的基本规则,并提前指出漏洞,以便您,专家,可以让我直截了当.

基本规则

  • 您的应用程序是一个 javascript 浏览器应用程序 - 它可能使用 AngularJS,但也可能是定制的.它通过 REST 调用与服务器通信.比方说,jQuery $ajax 调用.

  • 服务器是无状态的:没有会话管理.

  • 应用使用 JWT 作为主要身份验证令牌(OAuth2 中的访问令牌"),并使用秘密签名密钥在服务器上对其进行验证

  • 忽略 cookie 的其他重要优势:浏览器管理、编码不良的机会较少等.对于这场战斗,我想考虑绝对安全性,并假设我们可以胜任地编写任何一种机制.

  • 忽略 cookie 的其他缺点,例如非浏览器应用程序等.在这场战斗中,我们只关注基于浏览器的 javascript 应用程序.

  • 在非 cookie 方法中,您使用标头还是请求正文来传输令牌都没有关系;使用本地存储还是会话存储也无关紧要 - 忽略那里的任何安全差异.是的,我知道从技术上讲 Cookie 使用标头,请忽略它.


简而言之,我们只对比较 browser-handles-tokens 与 your-javascript-handles-tokens 以及比较 XSS 和 CSRF 安全风险感兴趣.


参赛者

在红色角落,Auth0:本地存储优于 Cookie,因为 XSS 比 CSRF 更容易修复

在蓝色角落,Stormpath:Cookie 胜过头文件,因为实际上 CSRF 比 XSS 更容易修复.

(下面详细摘录了两个论点)

选择的武器

XSS 和 CSRF(我们将交替使用 CSRF 和 XSRF:C 似乎在文档中更受欢迎,X 在代码中更受欢迎)

这是我对攻击类型的超级简化总结:

假设您的无状态、经过 JWT 身份验证的 javascript 浏览器应用程序用于网上银行,而攻击者Evil Corp"想要提交 AJAX REST 调用,通过冒充您的用户将资金转移到他们的帐户.

XSS(跨站脚本)

(正如 Stormpath 指出的,有很多攻击媒介 - 我会选择一个)

Evil Corp 购买了用于密码输入的漂亮文本字段小部件的 github 帐户权限.他们知道您的银行网站使用它,因此当您输入密码并按回车键时,他们会更新它以提交 AJAX 请求以将资金转移到他们的帐户.您的构建系统愚蠢地提取更新并投入生产.

CSRF(跨站请求伪造)

Evil Corp 知道您的银行网站使用 cookie 中的 JWT 来验证交易,因此他们编写了一个网络应用程序,提交 AJAX 请求以将资金转移到他们的帐户.他们在自己的 evil.com 站点上托管此内容,并在您碰巧在另一个选项卡中登录到您的银行站点时,通过电子邮件(网络钓鱼)或其他方式将您引诱到那里.浏览器提交了来自 evil.com 的请求,但附加了您的 JWT,因为它会转到正确的站点:银行.

标准防御

针对 XSS 的防御是对您站点中的代码非常小心,以便您永远不会让浏览器处理用户输入的内容而不对其进行清理(删除 javascript 和 html),并且所有 3rd 方库(Evil's text字段小部件)在使用前经过审查.正如 Stormpath 正确指出的那样,这很难,几乎是不可能的.

针对 CSRF 的防御是使用一种双重提交 cookie 的形式.这意味着我们的服务器会创建一个令牌(安全的随机字符串)并将其发送到我们的 Javascript 浏览器应用程序中的可读 cookie(按照惯例称其为XSRF-TOKEN"),我们的 Javascript 将它发送回标头或正文中的每个请求.

实际上,double-sumbit-cookie 只是对 CSRF 的一种防御,但其他一些需要有状态的服务器会话,没有其他(我认为!)提供更好的保护.也可以通过将令牌放入 JWT 并在服务器端将其与标头或正文中的令牌进行比较来实现无状态.

但这种防御的真正 CSRF 破坏质量是同源策略意味着只有我们的应用程序从我们的域加载的 javascript 可以读取该 cookie.因此,即使 evilcorp.com 上的 javascript 可以将我们的 cookie 与其请求一起发送,它也无法嵌入我们的 XSRF-TOKEN,因为它首先无法读取地点.

真正简化CSRF:

  • CSRF 攻击有效,因为附加 cookie 的浏览器仅取决于请求的目的地.
  • CSRF 防御之所以有效,是因为 Javascript 对 cookie 的访问取决于 Javascript 的来源.

Auth0 的参数

<块引用>

处理 XSS 比 XSRF Coo​​kie 更容易允许从服务器端设置 HttpOnly 标志,因此它们只能在服务器上访问而不是从 JavaScript 访问.这很有用,因为它保护该 cookie 的内容被注入访问客户端代码 (XSS).由于令牌存储在本地/会话中存储或客户端 cookie,它们容易受到 XSS 攻击让攻击者访问令牌.这是一个合理的担忧,并且出于这个原因,您应该将您的代币到期时间保持在较低的水平.

但是如果你想想 cookie 的攻击面,主要的攻击面之一是XSRF.现实情况是,XSRF 是最容易被误解的一种攻击和普通开发人员甚至可能不了解风险,因此很多应用程序缺乏反 XSRF 机制.然而,每个人都明白什么是注射.简单地说,如果你允许在您的网站上输入,然后在不转义的情况下进行渲染,您对 XSS 开放.所以根据我们的经验,更容易保护对抗 XSS 胜过防御 XSRF.除此之外,反 XSRF 是并非内置在每个 Web 框架中.另一方面,XSS 很容易通过使用大多数情况下默认可用的转义语法来防止模板引擎.https://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies#xss-xsrf

Stormpath 的论点

<块引用>

Stormpath 建议您将 JWT 存储在 cookie for web 中应用程序,因为它们提供了额外的安全性,以及使用现代 Web 框架保护 CSRF 的简单性.HTML5 Web Storage 易受 XSS 攻击,攻击面更大区域,并且可以影响所有应用程序用户的成功攻击.https://stormpath.com/博客/where-to-store-your-jwts-cookies-vs-html5-web-storage/

还有:

<块引用>

我看到很多讨论将 cookie 与访问权相提并论令牌.虽然我们都被存储会话 ID 的系统烧毁在 cookie 中,并且该 cookie 不受保护,因此会被盗.那很糟糕,但这不是使用令牌的理由.这是避免的理由非安全、非 https cookie.https://stormpath.com/blog/token-auth-spa/>

我的看法

Stormpath 支持 cookie 的论点非常有说服力,但其中有一个漏洞,我没有看到他们清楚地解决:


双重提交 CSRF 防御依赖于这样一个事实,即我的 CSRF 攻击者无法访问我的 cookie:其中包含 XSRF-TOKEN 的 cookie.但是,在 XSS 攻击中,该 cookie 是不是和本地存储一样容易受到攻击?


XSS 漏洞利用可以在我的 域上运行 javascript,因此它可以读取与我的 javascript 相同的 cookie.(浏览器不知道这不是我的 Javascript)

从另一方面来看:本地存储受到同源策略的保护,就像可读的 cookie 一样.如果我使用 Auth0 方法,并且 XSS 攻击者知道如何在本地存储中找到我的 JWT 并使用它.同一个攻击者不能使用同一个 XSS 脚本来获取我的 XSRF-TOKEN cookie 并使用它吗?

这两种攻击都要求他们阅读和理解我的 javascript 应用程序,但这在他们的浏览器中.

那有什么区别呢?一个真的比另一个更安全吗?为什么?

解决方案


放弃所有希望,除非你能抵御 XSS!

根据其他标准选择适合您的方法,因为两者同样安全,同样不安全.


如果你使用 cookie,你绝对应该使用双重提交 cookie 防御,或者类似的东西,因为它在没有 XSS 的情况下确实保护你免受 CSRF 的攻击.也就是说,如果你不这样做,你肯定会受到 CSRF 攻击——来自其他域——甚至不需要 XSS 漏洞利用的工作.

但无论哪种方式,您的源代码都是公开可用的(浏览器中的 JavaScript),因此对于一个有动力的黑客来说,找到从本地存储中提取哪个令牌和读取您的 XSRF-TOKEN cookie 之间的努力没有显着差异.如果 Evil Corp 可以让一些 JavaScript 在您的域中运行——那就是 XSS——那么你就完蛋了.

您可能要考虑的与安全无关的标准:

  • Cookie 很方便,因为您无需编写 JavaScript 代码来管理令牌 - 只需 XSRF.

  • 重定向也会变得更加自动化,如果您想使用它.

  • 本地存储更容易适应非浏览器应用程序 - 从服务器的角度来看,也就是说,因为如果你写一个 Java 中的 Android 应用程序不想处理 cookie,你的服务器不会'不需要区分 in 和浏览器,因为它不使用 cookie.

无论如何,请自行决定,但要小心您编写的 JavaScript 您使用的第 3 方 JavaScript!

I'm building a JWT-based (JSON Web Token) authentication mechanism for an browser-based Javascript web app, working with a stateless server (no user-sessions!) and I want to know, once and for all, if using storing my JWT token in a cookie will protect my token from XSS attacks, or if there is no protection, so there's no real advantage over using browser local storage in my Javascript app.

I have seen this question asked and answered in SO and in many blogs, but I've never seen an answer that really satisfies me.


This question was originally held on the basis that it solicits opinion - and given my original wording, rightly so. So let me make it clear here and now that I don't want an opinion based on vague notions of developer laziness or such - that's what the ground rules are meant to eliminate. What I want is an evidence-backed Yes/No answer. Either:

  • "Yes, cookies can be protected from XSS and CSRF and here's how" or
  • "No, by protecting your cookies from CSRF, you always open them up to the same kind of XSS attack that made cookies a good idea in the first place"

So I'm going to restate the question, with some simplifying ground-rules, and point out the holes in advance, so that you, the experts, can set me straight.

Ground rules

  • Your app is a javascript browser app - it might be in AngularJS, but it might be custom-built. It communicates with the server via REST calls. Let's say, jQuery $ajax calls.

  • The server is stateless: there is no session management.

  • The app users JWTs as the main authentication token ('access token' in OAuth2 parlance) and validates them on the server using a secret signing key

  • Ignore other important advantages of cookies: browser management, less chance of coding poorly, etc. For this battle, I want to consider the absolute security, and assume we can competently code either mechanism.

  • Ignore other disadvantages of cookies, such as non-browser apps, etc. For this battle we are only concerned with a browser-based javascript app.

  • It doesn't matter whether you use a header or a request body to transmit tokens in the non-cookie approach; nor does it matter if you're using local storage vs session storage - ignore any security differences there. And yes I know that technically Cookies use headers, ignore that.


In a nutshell, we're only interested in comparing browser-handles-tokens vs your-javascript-handles-tokens and the comparative XSS and CSRF security risks.


The contestants

In the red corner, Auth0: Local Storage beats Cookies, because XSS is easier to fix than CSRF

In the blue corner, Stormpath: Cookies beats headers, because actually CSRF is easier to fix than XSS.

(excerpts of both arguments in detail below)

Weapons of choice

XSS and CSRF (we'll use CSRF and XSRF interchangeably: the C seems to be more popular in documentation, the X in code)

Here's my super-simplified summary of the attack types:

Let's assume your stateless, JWT-authenticated, javascript browser app is for online banking and the attacker, "Evil Corp", wants to submit an AJAX REST call that transfers funds to their account by impersonating your users.

XSS (Cross-site scripting)

(As Stormpath points out, there are many attack vectors - I'll pick one)

Evil Corp buys the github account rights for the nifty text field widget you use for password entry. They know your bank site uses it, so they update it to submit AJAX requests to transfer funds to their account when you type in your passord and hit enter. Your build system foolishly pulls the update and puts in production.

CSRF (Cross-Site Request Forgery)

Evil Corp knows your bank site uses JWTs in cookies to authenticate transactions, so they write a web app that submits AJAX requests to transfer funds to their account. They host this on their own evil.com site, and lure you there with an email (phishing) or some other way, when you happen to be logged into your bank site in another tab. The browser submits the request from evil.com, but attaches your JWT becaues it's going to the correct site: the bank.

Standard defences

The defence against XSS is to be very careful about the code in your site so that you never let the browser process something the user types in without sanitizing it (removing javascript and html) and that all the 3rd party libraries (Evil's text field widget) are vetted before being used. As Stormpath rightly points out, this is hard, bordering on impossible.

The defence against CSRF is to use a form of double-submit-cookie. This means our server creates a token (securely random string) and sends it to our Javascript browser app in a readable cookie (call it "XSRF-TOKEN" by convention), and our Javascript sends it back in a header or body with every request.

Actually, double-sumbit-cookie's are only one defence agasint CSRF, but some others require stateful server sessions and no other (I think!) offers any better protection. The statelessness can be achieved by also putting the token in the JWT and comparing it on the server side with the one that comes in the header or body.

But the real CSRF-busting quality of this defence, is that same-origin-policy mean that only the javascript that our app loaded from our domain can read that cookie. So even if the javascript on evilcorp.com can send our cookies with its requests, it can't embed our XSRF-TOKEN because it can't read it in the first place.

To really simplify CSRF:

  • CSRF attacks work because a browser attaching a cookie depends only on the destination of a request.
  • CSRF defences work because Javascript access to a cookie depends on the origin of the Javascript.

Auth0's argument

It's easier to deal with XSS than XSRF Cookies have this feature that allows setting an HttpOnly flag from server side so they can only be accessed on the server and not from JavaScript. This is useful because it protects the content of that cookie to be accessed by injected client-side code (XSS). Since tokens are stored in local/session storage or a client side cookie, they are open to an XSS attack getting the attacker access to the token. This is a valid concern, and for that reason you should keep your tokens expiration low.

But if you think about the attack surface on cookies, one of the main ones is XSRF. The reality is that XSRF is one of the most misunderstood attacks, and the average developer, might not even understand the risk, so lots of applications lack anti-XSRF mechanism. However, everybody understands what injection is. Put simply, if you allow input on your website and then render that without escaping it, you are open to XSS. So based on our experience, it is easier to protect against XSS than protecting against XSRF. Adding to that, anti-XSRF is not built-in on every web framework. XSS on the other hand is easy to prevent by using the escape syntax available by default on most template engines. https://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies#xss-xsrf

Stormpath's argument

Stormpath recommends that you store your JWT in cookies for web applications, because of the additional security they provide, and the simplicity of protecting against CSRF with modern web frameworks. HTML5 Web Storage is vulnerable to XSS, has a larger attack surface area, and can impact all application users on a successful attack. https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/

Also:

I see a lot of discussions where cookies are pitted against access tokens. While we’ve all been burned by systems that store a session ID in a cookie, and that cookie is not secured and thus gets stolen. That sucks, but its not a reason to use tokens. Its a reason to avoid non-secure, non-https cookies. https://stormpath.com/blog/token-auth-spa/

My take

Stormpath's argument in favour of cookies is pretty convincing, but there's a hole in it that I don't see them addressing clearly:


The double-submit CSRF defence relies on the fact that my CSRF attacker cannot access my cookie: the one with the XSRF-TOKEN in it. But isn't that cookie just as vulnerable in an XSS attack as local storage?


An XSS exploit can run javascript on my domain, so it can read the same cookies my javascript can. (The browser doesn't know that it isn't my Javascript)

To look at it from the other side: local storage is protected by the same-origin-policy just as much as a readable cookie. If I'm using the Auth0 approach, and an XSS attacker knows how to find my JWT in local storage and use it. Can't that same attacker use that same XSS script to grab my XSRF-TOKEN cookie and use that?

Both attacks require them to read and understand my javascript app, but that's out there in their browser.

So what's the difference? Is one really more secure than another, and why?

解决方案


Abandon all hope unless you can secure against XSS!

Or

Choose the approach that suits you based on other criteria because both are equally secure, equally insecure.


If you use cookies, you should definitely use the double-submit-cookie defence, or something similar, because it does protect you against CSRF in the absence of XSS. That is, if you don't do this, you're definitely open to CSRF attacks - from other domains - that don't even require XSS exploits to work.

But either way, your source code is publicly available (JavaScript in your browser) so for a motivated hacker, there is no significant difference in effort between finding which token to pull from local storage and reading your XSRF-TOKEN cookie. If Evil Corp can get some JavaScript running in your domain - that's XSS - then you're hosed.

Non-security-related criteria you might want to consider for your choice:

  • Cookies are convenient because you don't have to write JavaScript code to manage the token - only the XSRF.

  • Redirection becomes a little more automatic too, if you want to use it.

  • Local storage is easier to adapt to non-browser apps - from the server perspective that is, because if you write say, an Android app in Java that doesn't want to deal with cookies, your server doesn't need to make any distinction between in and the browser, since it's not using cookies.

Anyway, make up your own mind, but be careful about the JavaScript you write and the 3rd party JavaScript you use!

这篇关于cookie 是否可以保护令牌免受 XSS 攻击?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆