Cookie会保护令牌免受XSS攻击吗?

Rhu*_*arb 18 javascript security cookies access-token jwt

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

我已经在SO和许多博客中看到了这个问题并得到了回答,但我从未见过真正满足我的答案.


这个问题最初是在征求意见的基础上进行的 - 并且考虑到我原来的措辞,这是正确的.因此,让我在此处明确表示,我不希望基于开发人员懒惰等模糊概念的观点 - 这就是基本规则要消除的意义.我想要的是证据支持的是/否答案.或者:

  • "是的,可以保护cookie不受XSS和CSRF的影响,这就是" 或者
  • "不,通过保护您的cookie免受CSRF的攻击,您总是将它们打开到相同类型的XSS攻击,这使得cookie首先成为一个好主意"

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

基本规则

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

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

  • 应用程序用户JWT作为主要身份验证令牌(OAuth2用语中的"访问令牌")并使用秘密签名密钥在服务器上验证它们

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

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

  • 是否使用标头或请求主体以非cookie方式传输令牌并不重要; 如果您使用本地存储与会话存储也不重要 - 忽略那里的任何安全差异.是的,我知道技术上Cookies使用标题,忽略它.


简而言之,我们只对比较浏览器处理令牌与您的-javascript-handle-tokens以及比较XSS和CSRF安全风险感兴趣.


参赛者

在红色角落,Auth0:Local Storage击败了Cookie,因为XSS比CSRF更容易修复

在蓝角,Stormpath:Cookies击败标题,因为实际上CSRF比XSS更容易修复.

(以下详细介绍两个论点)

武器的选择

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

这是我对攻击类型的超简化摘要:

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

XSS (跨站点脚本)

(正如Stormpath指出的那样,有很多攻击向量 - 我会选择一个)

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

CSRF (跨站请求伪造)

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

标准防御

对XSS防御是要非常小心在你的网站上的代码,这样你永远不会让浏览器进程东西在用户类型,而消毒它(删除JavaScript和HTML)以及所有的第三方库(邪恶的文本字段部件)在使用之前经过审查.正如Stormpath正确地指出的那样,这很难,接近不可能.

对CSRF的防御是使用双提交cookie的形式.这意味着我们的服务器创建一个令牌(安全地随机字符串)和(按照惯例称之为"XSRF-TOKEN")以可读的cookie发送到我们的JavaScript浏览器的应用程序,以及我们的JavaScript的每个请求发回的标题或正文.

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

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

真正简化CSRF:

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

Auth0的论点

处理XSS比使用XSRF更容易Cookies具有允许从服务器端设置HttpOnly标志的功能,因此它们只能在服务器上访问,而不能从JavaScript访问.这很有用,因为它可以保护注入客户端代码(XSS)访问的cookie的内容.由于令牌存储在本地/会话存储或客户端cookie中,因此它们会受到XSS攻击,攻击者可以访问令牌.这是一个有效的问题,因此您应该保持令牌过期时间不足.

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

Stormpath的论点

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

也:

我看到很多关于cookie与访问令牌相关的讨论.虽然我们都被在cookie中存储会话ID的系统所烧毁,但该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应用程序,但这些都在他们的浏览器中.

那有什么区别?一个人比另一个人更安全,为什么?

Rhu*_*arb 5


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

或者

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


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

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

您可能需要考虑的非安全相关标准供您选择:

  • Cookie 很方便,因为您不必编写 JavaScript 代码来管理令牌——只需编写 XSRF。

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

  • 本地存储更容易适应非浏览器应用程序——从服务器的角度来看,也就是说,因为如果你写一个不想处理 cookie 的 Java 安卓应用程序,你的服务器不需要做任何区分in 和浏览器之间,因为它没有使用 cookie。

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