我们最近收到了一份包含以下内容的安全报告:


没有设置HttpOnly标志的Cookie


漏洞,我们显然已经在其中我们的内部应用程序。

应用的修复很简单,就像将Django的CSRF_COOKIE_HTTPONLY配置参数设置为True一样。

,这让我感到困惑。 Django文档说:


将CSRF cookie指定为HttpOnly并不能提供任何实用的保护,因为CSRF只是为了防止跨域攻击。如果攻击者可以通过JavaScript读取Cookie,则他们已经
已经在浏览器所知的同一个域中,因此他们可以
做任何自己喜欢的事情。 (XSS比CSRF的漏洞大得多。)

尽管该设置几乎没有实际好处,但是有时它是安全审核员所必需的。


这是否意味着这里没有实际的漏洞,我们只需要遵守安全审核规则?

#1 楼

正如joe所说,这样做并没有真正的安全好处。它是纯安全剧院。我想在文档中重点介绍以下内容:


如果启用了此功能,并且需要使用AJAX请求发送CSRF令牌的值,则您的JavaScript必须从在页面上而不是从cookie中输入隐藏的CSRF令牌形式输入。


HttpOnly标志的目的是使cookie的值在JavaScript中不可用,因此不能如果存在XSS漏洞,则被盗。但是CSRF令牌必须以某种方式可用,以便可以两次提交-毕竟这就是重点。因此,Django通过将值包含在隐藏的表单字段中来解决此问题。这否定了HttpOnly的全部好处,因为攻击者只能读取form字段的值而不是cookie。

评论


为了强调一下,请重新概括一下前两句话:HttpOnly标志的目的是使站点的JavaScript无法使用cookie的值,但是在基于Ajax的webapp中,CSRF令牌的整个功能都依赖于它可从您网站的JavaScript中获取。这就是使安全报告如此错误的原因。

–马克·阿默里(Mark Amery)
17年12月15日在10:29



#2 楼

那是对的。这是一个误报,向您提供此发现的人并不了解他们的不幸经历。知道mitm和csrf攻击风险的人永远不会向您提供此保护。

评论


尽管此参数在特定情况下为true,但建议默认情况下采用严格的安全设置(包括使用httponly),并且仅在应用程序确实需要此设置且确实确定松动安全设置时才使用不太严格的设置。在特定情况下不会造成伤害。换句话说:除非有原因,CSRF cookie不能为httponly,否则也应为httponly。因此,我实际上会同意安全报告,因为在任何可能的情况下都没有安全默认值是一个坏主意。

– Steffen Ullrich
17/12/15在5:05



@SteffenUllrich如果JS无法提供双重提交令牌,怎么办?有问题的Django选项不仅可以设置标志。看我的答案。

–安德斯
17年12月15日在5:22

@Anders:您在漂亮答案中引用的陈述与问题和答案显示的图片不同。并且,这与我的评论“与...不冲突”,除非存在CSRF cookie不能为httponly的原因,否则也应为httponly。显然,在这种情况下,有一个原因不应该将它设为httponly,并且您已经在答案中显示了它。

– Steffen Ullrich
17/12/15在5:36



@SteffenUllrich虽然我总体上同意您的观点,但鼓励人们自己思考复杂的安全性(“除非有CSRF cookie不能为httponly的原因,否则也应该为httponly”)可能比清楚地说“是的,CSRF Cookie是一个例外,您可以将它们设置为httponly,因为它们的工作不需要httponly来确保安全。”它鼓励人们将推理应用到案件不太清楚的其他地方,并且最终可能导致错误(不安全)结果。

–乔纳斯·谢弗(JonasSchäfer)
17年12月15日在8:34

@joe是的,他们会为您支付一份完整报告的费用,通常,该标志是安全问题。除非您说这是“超出范围”,否则我希望它会在报告中再次提及。不要期望渗透测试者能够了解您所使用的环境或所选框架的100%,这是一个漏洞,由您自己来确定业务风险

– McMatty
18年11月29日在23:51

#3 楼

我认为这里的主要困惑是Django文档正在专门讨论Cookie的CSRF用例。为了了解为什么httpOnly标志在阻止CSRF方面没有增加价值,您需要同时了解CSRF和cookie的工作原理。

CSRF是第3方触发用户浏览器向您的浏览器发出请求时服务器,并且浏览器会自动将服务器的Cookie和请求一起发送给您,这与预期的一样。您不希望服务器将这个请求解释为实际上来自用户,因此您使用CSRF缓解技术。缓解CSRF的全部目的是能够检测到请求何时不是来自您自己的域(即来自与您的应用程序进行交互的用户)。

简而言之,cookie的工作原理:用户的浏览器向您的域/服务器发送请求,它将自动发送与您的域关联的所有cookie,而不考虑httpOnly标志。因此,Cookie允许您的客户端或服务器将信息附加到用户的浏览器,该信息将随任何后续请求一起自动返回到您的服务器。带有httpOnly标志的Cookie无法从javascript访问。它们可能不应该被视为存储信息的安全场所,但是它们确实提供了广告功能。

回到使用cookie实现的CSRF(在这种情况下,httpOnly标志是没有意义的),CSRF的症结在于他们不需要读取用户的cookie,他们只需要用户的浏览器将关联的cookie连同网络请求,他们强迫它发送。通常,httpOnly标志确实提供了价值,因为它防止客户端访问这些cookie,并且如果服务器返回任何cookie,则可能应将它们设为httpOnly。如果您在CSRF中使用cookie,则不应这样做,而应该花时间重新思考它,而不是将其设置为httpOnly cookie。因此,通常来说,这似乎是一个很好的经验法则-您的服务器不应发送任何非httpOnly cookie,除非它专门用于客户端javascript。

评论


我真的很喜欢这个完整的答案。谢谢。

–尼古拉斯·雷农(Nicolas Renon)
20年1月10日在18:32

#4 楼

防止双重提交的CSRF预防的唯一方法是通过在cookie中发送现时值。如果将其发送到HTTP响应正文中,则在某些情况下,可以通过发送跨域请求的脚本(如果您已允许该页面使用CORS)来解析该脚本,这将失去防御CSRF的整个目的。这个想法是域X上的脚本无法获得域Y上的cookie的值,这是Web安全的主要支柱之一。

使用HTTPOnly cookie,您将无法使用使用最常用的方法来防止CSRF攻击-即通过Cookie和页面上能够读取Cookie的脚本两次提交随机数。该技术的工作原理如下:

1)生成存储在会话中的服务器上的随机数值。它可以是会话ID本身,也可以是存储在与会话相关联的数据中的内容。

2)通过cookie头将其发送给客户端,而无需使用HTTPOnly,请使用一些Javascript抓取并存储它(例如短期或在sessionStorage中)

3)将每个要保护其免受CSRF的请求提交。该请求将在cookie中具有sessionId,并且在请求正文中或URL查询字符串中(例如,对于GET请求)将具有该现时值。如果您担心现时日志中的现时数变多,可以使用此现时数来使用Web加密与HMAC签署请求有效负载

4)服务器将查找会话数据,并检查如果现时不匹配,则抛出错误并生成另一个现时并发送cookie。请确保仅在cookie中发送随机数。

不幸的是,许多“安全审核”工具开始标记未标记httpOnly的cookie,并建议添加此标记。可悲的是,这个标志比没有用的情况更糟:它是安全剧院。

我只在谈论httpOnly标志。这比没用还糟,因为它使您认为自己躲开了某种形式的子弹,而实际上仍然可能发生相同类型的攻击:攻击者需要制作脚本以将Cookie发送到其服务器,因此他们也可能拥有该脚本会在您授权的会话的上下文中执行实际的请求,就像他们拥有您的cookie一样执行它们。他们会提前编写脚本。没有真正的攻击者会在凌晨3点坐在那里提出请求,因为受害者最终激活了向其发送cookie的脚本。该脚本很有可能已经被预先编程以执行所需的操作。而且,如果不存在httpOnly cookie,人们将更关心对Javascript输出进行清理以防止XSS,这是防止这种攻击的唯一正确方法。

评论


“如果将其发送到HTTP响应正文中,则可以通过发送跨域请求的脚本来解析它……”除非您严重搞砸了CORS配置,否则这是错误的,这本身就是一个非常严重的缺陷。 SOP防止跨源请求被原始脚本读取。这种方法为CORS的灾难性错误配置提供了一些深度防御,但这种DiD带来的边际安全收益远远小于使用比Double-submit cookie更为安全的CSRF保护所获得的收益。容易绕开。

– CBHacking
19/12/3在20:42



“使用HTTPOnly cookie,您将无法使用最常见的方法来防止CSRF攻击-即通过cookie和页面上的脚本(可读取cookie)重复提交一次随机数。”您能否提供有关此技术的更多背景知识? “ ...防止XSS,这是防止这种攻击的唯一正确方法。”我相信XSS问题与CSRF问题正交。

–科林
19/12/4在1:24



@CBHacking谢谢您,我已经更新了答案,以使您更清楚地知道,仅当您错误地处理CORS或无法使用HTTPS时,才应显示该漏洞。

–格雷戈里·玛格沙克(Gregory Magarshak)
19/12/4在3:05

@collin有帮助吗?

–格雷戈里·玛格沙克(Gregory Magarshak)
19/12/4在3:15

@GregoryMagarshak会话令牌的HMAC(已经是事实上的随机数)或与用户(最好是会话)相关的其他一些不可预测的值。这样可以防止cookie植入攻击,标头注入(用于添加cookie)攻击,会话固定类型攻击,并且至少部分避免了对令牌使用错误的PRNG的风险(尽管这是会话令牌的安全性问题)是)。它不需要额外的服务器端状态,可以使用或不使用cookie来完成,并且即使公开CSRF令牌也不公开会话令牌。

– CBHacking
19/12/4在3:40



#5 楼


将CSRF cookie指定为HttpOnly并没有提供任何实际的保护,因为CSRF只是为了防止跨域攻击。


这可以用更一般的方式规定

通过定义,将cookie指定为HttpOnly只能防止通过document.cookie或等效的JS方法进行访问。它不会阻止由JS代码引起的任何HTTP交互; JS可以启动用户通过HTML元素进行的任何交互(例如表单提交)。事物的开始方式没有有意义的区别。实际上,您可以通过指向用户键入当前页面或链接到当前页面的某些页面的URL来声明“用户已启动它”。

“视频自动播放”的概念定义不清,无法可靠地防止的原因:构成用户自愿启动视频的行为是用户界面概念,而不是DOM(文档对象模型)概念。浏览器不知道用户会做出自动手势来播放视频,除非视频在用户进行任何移动之前就开始播放(例如“向下滚动的空间”)。 (在某些情况下,您可以尝试“捣蛋”自动播放,例如可以尝试“捣蛋”(检测,黑名单)烦人的Web广告,或与第三方域共享信息,但不能保证覆盖范围。)

除非在某个域上完全关闭了JS,否则仅应假定由网站脚本执行由网站控制的框架内的任何用户操作。一个现代的Web,谁在大多数域中完全关闭了JS?几乎没有人。

因此,普遍的观察结果是:

将任何cookie都指定为HttpOnly并不能提供任何实际的保护,以防止任何攻击执行用户可能执行的操作的攻击通过网站的界面。

请注意,读取所有cookie(包括标记为HttpOnly的cookie)不是由网站界面完成的,只能使用浏览器的Inspector工具或通过HTTP发送的cookie的HTTP代理来完成。

#6 楼

可以在Django的反CSRF cookie中省略httpOnly属性,因为与其他许多答案(甚至是突出显示的问题)一样,在加载了未授权来源的受害浏览器中运行的javascript代码将无法从授权来源读取经过身份验证的响应,具有或不具有属性的属性,取决于“相同来源策略”。

(不要将会话cookie的严格要求与反CSRF cookie的严格要求混在一起)。

Django期望开发人员在HTML表单中填充反CSRF令牌与XSRF-TOKEN cookie相关(或相同)。

https://github.com/django/django/blob/f283ffaa84ef0a558eb466b8fc3fae7e6fbb547c/django/middleware/csrf.py#L136

Django的作者非常谨慎地规定了Secure属性的需要(该属性同时适用于会话cookie和反CSRF)。他们可能还提到需要添加Strict-Transport-Security响应标头来避免cookie注入和/或通过允许浏览器滑入http://链接并重写未加密的流量来窃听整个交互。

框架作者对httpOnly属性并不严格,因为由于具有相同来源策略,未经授权的来源将无法通过他们为浏览器生成的javascript代码读取cookie;他们的服务器端脚本试图从授权来源获取表单详细信息和响应标头,将仅收到未经身份验证的响应。

我只是偶然遇到了一个严格的要求,即当httpOnly用作单页应用程序的唯一来源时,不允许XSRF-TOKEN用于cookie。依靠XSRF-TOKEN响应cookie的SPA仍然是安全的。同样,由于“相同来源策略”,未经授权的来源将无法读取正确的XSRF-TOKEN响应Cookie。而且,未经授权的服务器端脚本也将无法预取正确的XSRF-TOKEN响应cookie(同样,因为脚本缺乏对授权服务器的身份验证)。

https://github.com / expressjs / csurf#single-page-application-spa

#7 楼

虽然CSRF令牌在具有受CSRF保护的表单的页面上不是秘密(并且可以使用XSS窃取),但是在某些页面中可能没有表单的XSS漏洞。
在那里,您只能从以下位置获取令牌: Cookie,但不是来自隐藏字段。
在这种情况下,使用HttpOnly cookie可以提高安全性。

仍然存在一种通过javascript请求包含表单的页面来获取令牌的方法。可能有防止这种情况的方法,但是在大多数站点上,这种攻击是可能的。

评论


如果没有表单的Paget上存在XSS漏洞,我可以只请求具有表单的页面并读取令牌(一些额外的工作,但不是很多)。如果存在XSS漏洞,为什么我仍然需要CSRF?我可以做我想做的。

–安德斯
17年12月22日在14:23

这就是重点。提您的问题:CSRF保护是降低XSS危险的一种方法。如果注入一些试图提交POST请求的脚本,则需要从某个地方获取CSRF令牌。如您所说,很有可能尝试通过加载另一个包含表单的页面来提取它。

– allo
17年12月22日在14:27

@allo不,CSRF保护不会使XSS的危险性稍差,因此宣称它是完全不负责任的!必须使用注入XSS的脚本向具有CSRF表单令牌的任何页面发出同源请求的GET请求,或者仅使用JS自己设置cookie(假设它没有以任何方式向会话进行身份验证,通常这是不合法的)。 t)只是微不足道的减速带。假装这样做会使您安全,只是一厢情愿,任何称职的攻击者都会绕过此“保护”,甚至没有注意到它在那儿。

– CBHacking
19/12/3在20:36



我提出了一个问题,即HttpOnly有什么优势,而不是它是否消除了XSS漏洞。在您上面的评论中,我阐明并描述了仍然可以用来规避HttpOnly提供的额外保护的方法。我明白您的意思,但是我的帖子和评论已经包含此设置能够提供的安全性限制。我认为您应该将您的观点作为问题的附加答案,因为与我的回答相比,您对问题的回答更多,并且您的观点足以写出答案。

– allo
19/12/4在15:04