摘要

内容安全策略是一种Web平台机制,旨在缓解现代Web应用程序中的顶级安全漏洞跨站点脚本(XSS)。在本文中,我们仔细研究了采用CSP的实际好处,并在实际部署中识别出重要的aws,导致所有不同策略的94.72%被绕过。

我们的互联网范围内的分析基于来自超过10亿个主机名的大约1000亿页的搜索引擎语料库;结果涵盖了1,680,867个主机上的CSP部署,以及26,011个独特的CSP策略(迄今为止最全面的研究)。我们介绍了CSP规范的安全相关方面,并对其威胁模型进行了深入分析,重点关注XSS保护。

我们确定了三种常见的CSP绕过类并解释了它们如何破坏策略的安全性。

然后,我们转向对因特网上部署的策略进行定量分析,以了解其安全性。我们观察到15个域中最常用于加载脚本的白名单中有14个包含不安全的端点;因此,75.81%的不同策略使用允许攻击者绕过CSP的脚本白名单。总的来说,我们发现94.68%的试图限制脚本执行的策略是无效的,99.34%的CSP主机使用的策略对预防XSS没有好处

最后,我们提出了 “strict-dynamic” 关键字,这是对规范的补充,有助于创建基于加密nonces的策略,而不依赖于域白名单。我们讨论了在复杂应用程序中部署这种基于随机数的策略的经验,并为Web开发者提供了改进其策略的指导。

介绍

XSS — 将攻击者控制的脚本注入Web应用程序的上下文的能力,可以说是最臭名昭着的Web漏洞。自从2000年CERT公告中第一次正式引用XSS以来,几代研究人员和从业者已经研究了检测,预防和减轻这个问题的方法

尽管有这些优点,XSS仍然是网络上最普遍的安全问题之一,随着网络的发展,不断发现新的变化。

如今,CSP(内容安全策略)是针对XSS的最有前途的对策之一。

CSP是一种声明性策略机制,允许Web应用程序开发人员确定浏览器可以加载和执行哪些客户端资源。通过禁止内联脚本并仅允许受信任的域作为外部脚本的源,CSP旨在限制站点执行恶意客户端代码的能力。因此,即使攻击者能够找到XSS漏洞,CSP也可以通过防止利用漏洞来保护应用程序安全(攻击者无法在不控制可信主机的情况下加载恶意代码)

在本文中,我们介绍了对Web上CSP部署安全性的第一次深入分析的结果。
为了做到这一点,我们首先通过审查其威胁模型,分析可能的配置缺陷并列举允许攻击者绕过其保护的鲜为人知的技术来研究CSP的保护能力。

我们使用从Google搜索索引中提取的现实世界CSP政策进行大规模的实证研究。基于此数据集,我们发现目前至少有1,680,000个Internet主机部署了CSP策略。在对我们的数据集进行规范化和重复数据删除之后,我们确定了26,011个独特的CSP策略,其中94.72%可以轻易绕过,攻击者可以使用自动化方法来查找允许破坏CSP保护的端点。即使在许多情况下,在部署CSP方面花费了相当多的工作,但90.63%的当前策略包含通过允许执行内联脚本或从任意外部主机加载脚本来破坏任何XSS保护的配置。我们数据集中只有9.37%的策略具有更严格的配置,并且可以防范XSS。但是,我们发现至少有51.05%的此类政策仍然可以绕过,因为 script-src 白名单中存在微妙的错误策略配置或源自不安全端点的原因。

根据我们的研究结果,我们得出结论,在复杂的应用中保持安全的白名单在实践中是不可行的;因此,我们建议改变CSP的使用方式我们建议通过指定脚本可以执行的URL白名单来指定信任的模型应该替换为基于nonces和hashes的方法,已经由CSP规范定义并且可以在主要的浏览器实现中使用。

在 nonce-based 的策略中,应用程序不是将主机和域列入白名单以执行脚本,而是在CSP策略中为合法的应用程序控制脚本的HTML属性提供一次性的不可猜解的 token。

用户代理(浏览器)只允许执行其 nonce 与策略中指定的值匹配的那些脚本;攻击者并不能知道易受注入攻击页面的标签的 nonce 的值,因此无法执行恶意脚本。为了简化这种 nonce-based 的方法的过程(这种方式在动态生成的脚本的执行上会有无法生成 nonce 的弊端),我们为’script-src’提供了一个新的CSP源表达式,暂时称为’strict-dynamic’。使用 “strict-dynamic”,动态生成的脚本会从创建它们的可信脚本中隐式继承nonce。通过这种方式,已经执行的合法脚本可以轻松地向DOM添加新脚本,而无需进行大量的应用程序更改。因此,即使攻击者发现了 XSS 漏洞,但是却不知道正确的nonce,也还是无法滥用此功能,因为它们无法在第一时间执行脚本。

为了证明这种方法的可行性,我们提出了一个在流行的应用程序中采用基于随机数的策略的实际案例研究

我们的贡献可归纳如下:

  • 我们介绍了对CSP安全模型的第一次深入分析的结果,分析了对标准提供的Web错误的保护。我们确定了共同的策略错误配置,并提出了三类绕过 CSP 的方法。
  • 我们通过从Google搜索索引中提取策略,对实际CSP部署的好处进行了大规模的实证研究。基于大约1060亿页的语料库,其中39亿页受CSP保护,我们确定了26,011个独特的政策。我们发现,由于政策错误配置和不安全的白名单条目,这些政策中至少有94.72%对缓解XSS无效。
  • 根据我们的观点,我们建议改变内容安全策略在实践中的部署方式:我们提倡基于nonce的方法,而不是白名单。为了进一步推广这种方法,我们提出了“strict-dynamic”,这是目前在Chromium浏览器中实现的CSP3规范的一个新特性。我们讨论了这种方法的好处,并提出了在流行的Web应用程序中基于nonce和strict-dynamic部署策略的案例研究。

内容安全策略

概述

内容安全策略(CSP)是一种声明性机制,允许Web作者在其应用程序上指定许多安全限制,会由支持该项技术的用户代理(浏览器)强制执行。

CSP旨在成为 “开发人员可以用来以各种方式锁定其应用程序,降低内容注入漏洞(…)的风险并降低其应用程序执行的权限的工具。“

CSP正在快速发展:目前正在进行规范的版本是CSP3,并且该标准由用户代理不均衡地实现。例如,Chromium具有完整的CSP2支持并实现了CSP3的大部分工作草案,在某些情况下落后于实验运行时标志,而Mozilla Firefox和基于WebKit的浏览器最近刚刚获得了完整的CSP2支持。在讨论CSP的细节时,我们不关注标准的任何特定修订,而是尝试提供跨实现和版本的广泛概述。

CSP策略在Content-Security-Policy HTTP响应头或<meta>元素中提供。

CSP的功能可分为三类:

1.资源加载限制

CSP最着名和最常用的是限制将各种子资源加载到开发人员允许的一组源(称为源列表)的能力。常用的指令是script-src,style-src,img-src和覆盖全部的default-src;表1中显示了管理资源的完整指令列表。作为一种特殊情况,script-src和style-src指令可以使用其他几个配置选项。这些允许对脚本和样式表进行更细致的控制,下面将对此进行讨论。

此处输入图片的描述

2.基于URL的辅助限制

通过监管所获取的子资源不能防止一些类型的攻击,但同样需要文档可以与之交互的可信来源的概念。一个常见的例子是 frame-ancestors 指令,它定义了允许构建文档以防止点击劫持的起源。类似地,base-uri 和form-action可以将URL作为<base#href><form#action>元素的目标,以防止一些 post-XSS攻击。

3.杂项连接和硬化选项

由于缺乏在Web应用程序中启用安全性限制的其他常用机制,CSP已成为几种松散安全功能的基础。这包括block-all-mixed-content 和 upgrade-insecure-requests关键字,可以防止混合内容错误并改善HTTPS支持;插件类型,限制允许的插件格式;反映了HTML5沙箱框架的安全功能的 sandbox。

为了使Web应用程序与对XSS有用的内容安全策略兼容,Web开发者通常必须重构应用程序逻辑生成的HTML标记,以及框架和模板系统。

特别是内联脚本,必须避免使用eval和等效构造,内联事件处理程序和javascript:URI,使用CSP友好的替代方法。

除了强制执行策略限制的默认行为之外,还可以在 Report-Only 模式下配置CSP,其中只记录违规但不强制执行。在这两种情况下,report-uri指令可用于发送违规报告,以通知应用程序所有者不兼容的标记。

源列表

CSP源列表(通常称为白名单)是CSP的核心部分,是指定信任关系的传统方式。例如,如清单1所示,应用程序可能选择仅信任其托管域以加载脚本,但允许来自cdn.example.org和third-party.org的字体或图像,并要求通过HTTPS加载帧,同时对其他资源类型不施加任何限制。

此处输入图片的描述

对于任何指令,白名单可以由主机名(example.org,example.com)组成,可能包括*通配符以将信任扩展到所有子域(*.example.org); scheme(https:,data:);和特殊关键字’self’,表示当前文档的来源,‘none’,强制执行空源列表并禁止加载任何资源。

从CSP2开始,作者还可以选择在白名单中指定路径(example.org/resources/js/)。
有趣的是,不能依赖基于路径的限制来限制可以加载资源的位置;

脚本执行的限制

由于现代Web应用程序中脚本的重要性,script-src指令提供了几个关键字,以允许更精细地控制脚本执行:

1.unsafe-inline

允许执行内联<script>块和JavaScript事件处理程序(有效地删除针对XSS的任何CSP保护

2.unsafe-eval

允许将字符串数据作为代码执行的JavaScriptAPI,例如eval(),setTimeout(),setInterval()和Function构造函数。否则,这些API将被具有script-src指令的策略阻止。

3.nonce

CSP nonce 允许策略指定一个一次性值,该值用作脚本的授权 token(script-src ‘nonce-random-value’)。将允许页面上具有正确的 nonce =”random-value”属性的任何脚本执行。

4.hash

CSP hash 允许开发人员列出页面内预期脚本的加密哈希值(script-src ‘sha256-nGA …’)。将允许执行其摘要与策略中提供的值匹配的任何内联脚本。

Nonce和hashes可以类似地与style-src指令一起使用,以允许通过nonce值加载内联样式表和外部CSS。

此处输入图片的描述

CSP的威胁模型

为了使CSP能够提供安全保护,它必须防止攻击者利用,否则会对应用程序的用户启用恶意操作。

CSP提供三种漏洞的保护

1.XSS:

在易受攻击的应用程序中注入和执行不受信任的脚本的能力(受script-src和object-src指令保护)

2.点击劫持:

通过在攻击者控制的页面上覆盖隐藏的帧来强制用户在受影响的应用程序中执行不需要的操作(通过限制框架祖先的框架来保护)

3.混合内容:

意外地从通过HTTPS传递的页面上的不安全协议加载资源(使用upgrade-insecure-requests和block-all-mixed-content关键字保护,并限制脚本和敏感资源加载到https :)。

因此,只有一小部分CSP指令对XSS保护有用。此外,在应用程序的上下文中执行恶意脚本的能力颠覆了所有其他指令所提供的保护

采用CSP的好处

由于一些流行的用户代理(浏览器)尚不支持CSP或者只支持部分支持,因此在主要安全机制失败的情况下,CSP应仅用作深度防御以阻止攻击尝试。因此,使用CSP的应用程序还必须采用传统的保护机制;例如,使用具有严格上下文转义的框架来生成标记,使用 X-Frame-Options 标头来防止点击劫持,并确保通过HTTPS获取安全页面上的资源。

设置内容安全策略的实际好处只有在主要安全机制已证明不足时才会出现–CSP可以帮助保护用户,当开发人员引入编程错误时,否则会导致XSS,点击劫持或混合内容错误。

然而,实际上 X-Frame-Options 的点击劫持保护很少被攻破,并且在现代用户代理中默认情况下已禁止活动混合内容(通过HTTP从HTTPS网页加载的脚本和其他活动内容)。因此,CSP的主要价值在于防止利用XSS,因为它是唯一可以通过CSP缓解并且通常可以减轻的漏洞类别。

防御XSS

CSP的安全优势主要集中在两个阻止脚本执行的指令:script-src和object-src(Adobe Flash等插件可以在嵌入页面的上下文中执行JavaScript),或者在他们缺省情况下的 default-src。

可以注入和执行脚本的攻击者能够绕过所有其他指令的限制。因此,使用不安全的 script-src 和 object-src 源列表策略的应用程序从CSP获得的优势就非常有限了。

对于提供有意义的安全性的其他指令,站点必须首先使用成功阻止脚本执行的安全策略。一般来说,非脚本指令可以作为对一些post-XSS 或 scriptless 攻击的防御,例如通过劫持表单URI来删除数据,或通过使用攻击者发布页面UI进行网络钓鱼,但只有当CSP作为XSS保护措施已经有效时,它们才能提高安全性。

为了实现防止不需要的脚本执行的主要目标,策略必须满足三个要求:

三大要求

  • 该策略必须同时定义script-src和object-src指令(或者default-src)

此处输入图片的描述

  • script-src源列表不能包含 unsafe-inline 关键字(除非附有nonce)或允许 data:URIs

此处输入图片的描述

  • script-src和object-src源列表不能包含允许攻击者控制响应的安全相关部分或包含不安全库的任何端点。

此处输入图片的描述

如果不满足任何这些条件,则该策略在防止脚本执行方面没有效果,因此无法防止内容注入攻击。

我们现在转向对端点类型的分析,这些端点在托管在白名单源上时允许攻击者绕过针对脚本执行的CSP保护。

脚本执行绕过

CSP的一个基本假设是,策略中列入白名单的域仅提供安全内容。因此,攻击者不能在此类列入白名单的来源的响应中注入有效的JavaScript。

在以下小节中,我们证明了在实践中,现代Web应用程序倾向于使用违反此假设的几种模式。

1.具有用户控制的回调的JavaScript

虽然许多JavaScript资源是静态的,但在某些情况下,开发人员可能希望通过允许请求参数设置在加载脚本时执行的函数来动态生成脚本的一部分。例如,在回调函数中包装JavaScript对象的JSONP接口通常用于允许加载API数据,方法是将其作为脚本从第三方域获取:

此处输入图片的描述

遗憾的是,如果策略中列入白名单的域包含JSONP接口,则攻击者可以使用它在易受攻击的页面上下文中执行任意JavaScript函数,方法是将端点作为带有攻击者控制的回调的<script>加载。如果攻击者可以控制JSONP响应的整个开始,他们将获得无约束的脚本执行。如果字符集受到限制,因此只有函数名称是可控的,它们可以使用诸如SOME之类的技术,这些技术通常在定性上等同于完整的,无约束的XSS。

2.反射或者符号执行

CSP脚本执行的限制可能(通常是偶然)被白名单源中的协作脚本规避。例如,脚本可以使用反射来查找并调用全局范围中的函数,如清单7所示。

此处输入图片的描述

这样的 JavaScript小技巧通常不会危及安全性,因为它们的参数处于其页面加载脚本的开发人员的控制之下。当这样的脚本通过检查DOM获取数据时技巧会出现问题,如果应用程序具有标签注入bug(攻击者可以执行任意函数,可能使用无约束的参数,绕过CSP,则可以部分地受到攻击者控制)。

一个实际的例子是流行的AngularJS库的行为,它允许创建具有强大的模板语法和客户端模板评估的单页面应用程序(清单8)。

此处输入图片的描述

为了实现其目标,AngularJS在页面的指定部分解析模板并执行它们。控制Angular解析的模板的能力可以被认为等同于执行任意JavaScript。默认情况下,Angular使用eval() 函数来评估沙箱表达式,这是没有unsafe-eval关键字的CSP策略所禁止的。但是,Angular还附带了一个CSP兼容模式“(ng-csp),其中表达式通过执行符号执行来计算,从而可以在CSP中调用任意JavaScript代码。

因此,可以从CSP中列入白名单的域加载Angular库的攻击者可以将其用作JS小工具来绕过脚本执行保护。即使被攻击的应用程序没有使用Angular本身,这也是可能的(唯一要求是将Angular库托管在script-src中列入白名单的域之一上)。因此,在受信任域中仅存在任何Angular库都会破坏CSP提供的保护。

3.非预期的JavaScript可解析响应

出于兼容性原因,Web浏览器通常很宽松地检查响应的MIME类型是否与使用响应的页面上下文匹配。任何可以在没有语法错误的情况下解析为JavaScript的响应(并且在第一个运行时错误之前出现攻击者控制的数据)可能导致脚本执行。

因此,可以使用以下类型的响应绕过CSP:

  • 具有部分攻击者控制内容的逗号分隔值(CSV)数据:

此处输入图片的描述

  • 回显请求参数的错误消息:

此处输入图片的描述

  • 用户文件上传,即使其内容已正确HTML转义或清理

因此,如果列入白名单的域托管具有此类属性的任何端点,攻击者可以“伪造”脚本响应并执行任意JavaScript。类似的问题适用于object-src白名单:如果攻击者可以上传将被解释为Flash的资源对象到被 ogject-src列入白名单的域,脚本可以执行。

值得注意的是,上述旁路模式都不会带来直接的安全风险,因此开发人员通常没有理由对其进行更改。但是,当应用程序采用CSP时,此类端点会成为安全问题,因为它们允许绕过策略。

更有问题的是,这个问题不仅影响应用程序的origin,还影响script-src中列入白名单的所有其他域。这些域通常包括可信的第三方和可能不了解CSP的CDN (因此没有理由识别和修复允许CSP绕过的行为)。

4.路径限制作为安全机制

为了解决基于域的源列表的不完整粒度问题,CSP2引入了将白名单约束到给定域上的特定路径的能力(例如example.org/foo/bar)。开发人员现在可以选择在受信任的域上指定特定目录以加载脚本和其他资源。

不幸的是,由于与处理跨域重定向有关的隐私问题,这种限制已经放宽。如果源列表条目包含重定向器(端点返回指向另一个位置的30x响应),则该重定向器可用于从白名单源中成功加载资源,即使它们与策略中允许的路径不匹配也是如此。

此处输入图片的描述

由于这种行为以及复杂Web应用程序中重定向器的普遍存在(通常用于OAuth等安全上下文中并防止引用泄漏),因此不能依赖路径限制作为CSP中的安全机制。

我们已经展示了一些看似良性的编程模式如何允许内容注入攻击者绕过CSP提供的脚本执行保护,从而消除策略的任何反XSS优势{其主要关注点。我们现在转而分析这种绕道对现实世界政策的影响。

CSP的实证研究

我们的工作目标是调查CSP在实践中提供的一般方法和保护能力。为此,我们进行了大规模的实证研究,以收集和分析现实世界的CSP策略。在本节中,我们描述了本研究的方法和结果。

问题研究

我们的研究分为两个主要部分。首先,我们的目标是了解CSP目前的使用情况;第二,我们要分析已部署策略的安全属性。

CSP如何在web上使用?

正如先前的研究所示,CSP采用率落后于安全社区的期望。因此,在我们的研究的第一部分,我们旨在阐明CSP的当前状态,以了解CSP的使用范围。此外,我们想了解CSP是专门用于XSS保护还是其他普遍存在的用例。由于许多主要的Web应用程序需要更改为与CSP兼容,因此尚不清楚CSP策略是否已用于XSS保护,或处于相当实验状态,其中仍然禁用强制执行。因此,我们感兴趣的是执行模式中的策略与仅报告模式下的策略之间的比率。在本研究的第二部分中,我们将使用强制策略进行安全性分析。

现实世界的CSP政策有多安全?

如第2节所述,有很多缺陷可能会使策略的保护能力无效。避免策略制定中的这些错误需要广泛的知识。在我们研究的第二部分,我们的目标是确定有多少策略是由错误影响的,因此可以绕过。我们还调查哪种错误最为普遍。此外,我们的目标是分析严格策略的安全性,特别是白名单的安全性。

方法论

在以下小节中,我们概述了用于从给定数据集中提取和分析内容安全策略的方法。

检测内容安全策略

为了从数据集中提取CSP策略,我们编写了一个系统。对于具有CSP策略的索引中的每个URL,我们提取了以下元组:

此处输入图片的描述

基于此元组列表,我们为每个主机提取了一组唯一策略,有效地删除了每个主机上的重复策略。

规范化CSP策略

多个网站自动生成包含随机nonces,hashes 或 report URIs 的CSP策略。在此过程中,某些生成例程会随机切换某些指令或指令值的顺序。为了使我们的数据集中的策略具有可比性,我们首先对策略进行了规范化。我们按照规范1中的描述实现了一个CSP解析器,并存储了每个CSP的解析副本,以便以后进行深入评估。对于每个策略,我们应用了以下规范化步骤:

  • 首先,我们删除了多余的空格并用柔性占位符替换所有变量值,例如nonces和report URIs。
  • 其次,我们对所有指令和指令值进行了排序和重复数据删除。

重复编写CSP

在我们的分析过程中,我们发现消息板和电子商务平台等现成的Web应用程序分布在许多不同的主机上,同时部署完全相同的CSP策略。为解决此问题,我们决定根据规范化的策略字符串对CSP进行重复数据删除。因此,我们的最终数据集包含我们在网络上找到的每个唯一策略的单个条目。

确定XSS保护策略

如前所述,CSP支持许多主要用于防御XSS的指令,例如img-src和frame-ancestors。由于我们的研究旨在评估策略在XSS缓解能力方面的安全性,因此我们需要一种方法来区分试图抵御XSS的策略与所有其他策略。根据我们的定义,XSS保护策略必须处于强制模式,并且必须至少包含以下两个指令之一:script-src或default-src

评估政策的安全性

为了评估是否可以绕过CSP策略来执行攻击者控制的脚本,我们进行以下检查:

1.使用 ‘unsafe-inline’:

如果没有指定脚本随机数,那么带有’unsafe-inline’关键字的策略本质上是不安全的。这样的策略是被视为可绕行的。

2.缺少 object-src:

指定script-src但缺少object-src指令(并且未设置default-src)的策略允许通过注入插件资源来执行脚本,如清单3所示。

3.在白名单中使用通配符:

如果安全相关的白名单包含通用通配符或URI方案(http:, https: or data:),则允许包含来自任意主机的内容,则策略也是不安全的。

4.白名单中的不安全来源:

当托管具有CSP旁路的端点的域列入白名单时,CSP的保护功能将变为无效。为了评估策略的安全性,我们编译了具有这种可绕过端点的主机列表。如果给定策略的白名单条目出现在此列表中,我们
政策是可绕过的。在下一节中,我们将概述如何创建此列表。

使用允许CSP byasses的端点标识域

为了识别CSP中白名单不安全的域,我们从搜索索引中提取了之前描述的实践之一的页面。如前所述,托管AngularJS库并公开JSONP端点是创建CSP绕过的众多方法中的两种。

JSONP 端点

为了识别JSONP端点,我们从搜索索引中提取了包含GET参数的所有URL,其中包含以下名称之一:callback,cb,json,jsonp。

随后,我们通过更改相应参数的值,请求资源并且检查更改的值是否能在返回值的开头反射出来,从而验证结果数据集

我们通过验证响应中允许的字符来检查所有端点是否允许完整的XSS或SOME攻击。根据我们的数据,39%的JSONP绕过允许任意JS执行,而其余的允许通过SOME攻击任意调用现有函数,在实际应用程序中被认为与完整XSS一样有害。

AngularJS:

对于AngularJS库,我们创建了一个小签名,该签名与源代码的特定部分(迷你版和非迷你版)相匹配。对于每个匹配,我们然后通过匹配包含的版本字符串来提取文件的版本。

结果与分析

网络上的CSP状态

我们使用Google的一个索引作为检测CSP策略的数据集。在此分析时,此特定索引包含大约1060亿个唯一URL,跨越10亿个主机名和1.75亿个顶级私有域.3我们认为此索引代表了当前的Web状态,因为所有URL都是由在我们分析前约20天的时间范围内使用Google抓取工具。

在此数据集中,我们发现3,913,578,446(3.7%)个网址带有CSP政策。但是,这个数字并不是CSP采用率的良好近似值,因为具有大量URL的应用程序可能在整个数据集中过多。在考虑跨域分布时,总体情况看起来不同:274,214个顶级私有域中仅有1,664,019(0.16%)的所有主机名都部署了CSP策略。在此列表中,仅使用少数不同的策略将100万个主机名映射到ve-commerce4应用程序之一。为了解决这个问题,我们使用规范化策略对数据集进行了重复数据删除。通过这样做,我们确定了26,011个独特的政策。

CSP 如何被使用

它有许多其他用例。因此,作为第一步,我们试图确定CSP是否用于其预期目的。图1显示了所有CSP指令的列表,按发生次数排序。该列表清楚地显示了script-src and/or default-src 指令在大多数策略中使用。相比之下,frame-ancestors指令,可用于控制框架行为页面的使用仅在8.1%的策略中使用。此外,在26,011个唯一策略中,只有9.96%处于仅报告模式,而其他90.04%处于强制模式。在这些数字中,我们看到明确的证据表明CSP意味着XSS保护。

此处输入图片的描述

CSP的一般安全性

为了评估检测到的CSP策略的安全属性,我们自动应用了之前的检查。基于对配置和白名单可绕行性的分析,我们观察到整个数据集中94.72%的策略不受XSS的任何保护。

重要的是要注意,其中一些策略不处于强制模式或不用于防止XSS;然而,即使对于XSS保护政策,可绕过政策的百分比也非常相似:94.68%。

不幸的是,大多数策略本质上都是不安全的。在XSS保护策略中,87.63%使用’unsafe-inline’关键字而未指定nonce,这实际上禁用了CSP的保护功能。

这个高的令人惊讶的数字可能是因为许多Web应用程序需要重写其大部分代码才能与CSP兼容其中一些页面可能仍处于过渡阶段,需要使用“unsafe-inline”关键字。虽然从长远来看这个问题可能会被解决,但许多策略都包含其他明显的问题。例如,我们确定9.4%的策略既不包含default-src,也不包含object-src指令。因此,攻击者可以通过注入能够执行JavaScript的恶意Flash对象来利用XSS漏洞。此外,21.48%的策略在script-src或default-src指令中使用通用通配符或URI方案(http:或https:),因此允许包含来自任意,可能受攻击者控制的主机的脚本。

鉴于这些值,似乎绝大多数策略都无法有效地防范XSS攻击。但是,由于CSP可能不成熟,因此早期采用问题可能会导致数字偏大。为了解释这一事实,我们编制了一套策略不包含微不足道的问题,例如’unsafe-inline’关键字或白名单中的通用通配符。总计,我们找到了符合这些条件的2,437条策略。我们观察到,通过我们的自动策略分析工具,我们仍然能够绕过这些严格策略的51.05%。

虽然这些旁路中的一些是由缺少 object-src 和 default-src 指令引起的,但大多数旁路是由script-src白名单中的不安全起源引起的。在下一节中,我们将详细讨论我们对白名单的分析。

白名单安全性

对于白名单中的每个主机,维护者需要确保攻击者无法注入恶意内容,这些内容可以通过<script><object>标记包含在内。如前所述,JSONP端点和AngularJS库是实现此目的的众多方法中的两种。如果即使只有一个域暴露这样的端点,CSP的反XSS功能也会变得无用。因此,白名单越大,维护相应政策的安全性就越困难。

作为我们分析的结果,我们得出结论,在传统的基于白名单的模型中部署CSP以防止XSS是不可行的,因为在实践中通常会破坏脚本执行限制。我们建议在第4节中通过制定CSP策略来解决此问题的方法,该策略用脚本nonces替换域白名单

CSP 提升

实际上,目前使用CSP的绝大多数网站都部署了一项不对XSS提供安全保护的策略。 除了明显的配置问题(具有’unsafe-inline’的策略和未指定object-src的策略),策略不安全的主要原因是script-src白名单的可绕行性。

在现代网络上,基于白名单域的方法(即使伴随路径)似乎过于灵活,无法很好的让开发人员阻止XSS。

与此同时,CSP已经提供了更细粒度的授予脚本信任的方法:加密 nonces和hashes。特别是,nonces允许开发人员显式地注释每个可信脚本(内联和外部),同时禁止执行攻击者注入的脚本。

为了提高CSP的整体安全性,我们提出了一种略微不同的编写策略的方法。应用程序维护人员应该应用基于nonces的保护方法,而不是依赖于白名单。以下清单描述了基于白名单的CSP策略和满足此策略的脚本:

此处输入图片的描述

不幸的是,此策略的白名单包含一个不安全的主机,因此描述的策略是不安全的。攻击者可以通过注入具有以下URL的脚本来滥用JSONP端点:https://example.org/script.js?callback= malicious_code。

为避免此问题,我们建议以下列方式重写此类策略:

此处输入图片的描述

通过使用 nonce ,脚本可以单独列入白名单。
即使攻击者能够找到XSS,nonce值也是不可预测的,因此攻击者无法注入指向JSONP端点的有效脚本。

CSP的一个有用功能是它允许集中执行安全决策。例如,安全团队可能会使用CSP来强制执行一组允许加载脚本的可信主机,而不是依赖开发人员的善意而不包括来自不受信任站点的脚本。然而,在单一的基于随机数的策略中,这是不可能的;资源只需要遵循白名单或随机数。因此,将白名单添加到基于随机数的策略会消除的优点。有趣的是,浏览器允许执行多个策略。如果为页面指定了两个策略,则浏览器会确保资源遵循这两个策略。(这一点在 2018 TCTF 的一道题中就涉及到了,两个同名的策略都有效)因此,此功能可用于获得两个方面的好处:一个基于nonces的策略可用于将单个脚本列入白名单,而另一个基于白名单的策略可用于集中执行安全决策。通过用逗号分隔两个策略,可以在同一个HTTP响应头中将这两个策略传送到客户端:

此处输入图片的描述

然而,当通过JavaScript将新脚本添加到页面时,会出现基于随机数的策略的另一个问题:因为JS库可能不知道CSP并且不知道正确的CSP 随机数,所以CSP将阻止动态插入的脚本执行,部分应用程序将失败。

在不依赖源列表的情况下,我们为script-src提出了一个新的源表达式:’strict-dynamic’。 ‘strict-dynamic’是CSP3规范草案5,在Chrome和Opera中实现。我们在后面会描述了一个流行的生产应用程序中的采用过程和结果。

将信任传播到动态脚本

在script-src源列表中添加建议的’strict-dynamic’关键字会产生以下后果:

  • 允许动态添加的脚本执行。实际上,这意味着策略将允许document.createElement(‘script’)创建的脚本节点,无论它们加载的URL是否在script-src白名单中。
  • 其他script-src白名单条目将被忽略。除非伴随有效的nonce,否则浏览器不会执行静态或解析器插入的脚本

这种方法背后的核心点是,通过调用createElement()添加的脚本已经被应用程序信任(开发人员明确选择加载和执行它们)。另一方面,发现标记注入bug的攻击者无法在不首先执行JavaScript的情况下直接调用createElement();并且攻击者无法在不知道策略中定义的适当nonce的情况下注入恶意脚本并执行JavaScript。

这种使用CSP的方式有望实现基于nonce的策略,其中执行脚本的能力由开发人员通过在可信脚本上设置nonce来控制,并允许信任通过设置’strict-dynamic’传播到下标。

例如,开发人员可以设置类似于以下内容的策略:

此处输入图片的描述

使用这样的策略,所有者需要向静态<script>元素添加nonce,但是可以确保只有这些可信脚本及其后代才会执行。

这种部署CSP的模式可以显着提高策略的安全性并促进采用。

strict-dynamic 案例研究

2015年2月,我们在Google地图活动中采用了基于白名单的强制执行内容安全政策,这是一个由400万月活跃用户使用的复杂且重量级的JavaScript网络应用程序。我们从一个简单的策略开始,包括一个nonce和整个origin,但必须逐步扩展它(在整个2015年进行5次重大更改)以应对应用程序,API和库中的更改,同时保持白名单路径的安全性和限制性可能。为了避免生产中断,我们不得不定期更新origin
来对API和内容服务基础架构的更改。这导致了script-src白名单的大小爆炸:它增长到15条长路径,遗憾的是仍然必须包含至少一个JSONP端点,从而在XSS保护方面损害了策略的有效性。

由于标记中的脚本已经到位,因此从基于白名单的方法切换到具有“strict-dynamic”的非常规策略不需要重构。该交换机还允许我们大幅简化策略,避免破坏,同时使其更安全,更易于维护(事实上,从那时起我们就不必对策略进行更改)。

到目前为止,我们已经在Google照片,云控制台,历史记录,文化学院和其他机构中部署了一个仅限于nonce-only的政策,其中包含“strict-dynamic”和非常少的电子邮件。

限制

使用“strict-dynamic”的基于随机数的策略可以提供更安全,更易于部署的CSP,但它们并不是XSS的灵丹妙药。作者仍需要注意安全性和兼容性方面的考虑因素:

安全性

  • 注入动态创建的脚本的src属性:使用’strict-dynamic’,如果XSS错误的根本原因是将不受信任的数据注入到传递给通过createElement()创建的脚本的src属性的URL中API,该bug将变得可利用,而使用基于白名单的策略,脚本的位置将仅限于策略中允许的源。

  • 注入nonced <script>:如果注入点位于开发人员信任的 <script>内,则攻击者将能够无限制地执行其恶意脚本。但是,传统政策仍然可以实现这一点。

  • post-XSS/scriptless 攻击:即使策略阻止攻击者在应用程序的上下文中执行任意脚本,其他有限但也具有破坏性的攻击仍可能。

兼容性

  • 解析器插入的脚本:如果应用程序使用诸如document.write()之类的API来动态添加脚本,即使它们指向列入白名单的资源,它们也会被“strict-dynamic”阻止。采用者必须重构此类代码以使用其他API(如createElement()),或者将nonce显式传递给使用document.write()创建的<script>元素。

  • 内联事件处理程序:’strict-dynamic’不会消除删除与CSP不兼容的标记的耗时过程,例如javascript:URI或内联事件处理程序。在采用CSP之前,开发人员仍需要重构这些模式。

尽管存在这些警告,但基于对Google内部数据集中数百个XSS错误的分析,我们预计大部分XSS将使用基于随机数的策略进行缓解,并且采用此类策略对于开发人员而言要比基于白名单的传统方法。

相关工作

2007年发表了第一篇提出将脚本列入白名单以阻止注入攻击的论文之一。名为Browser-Enforced Embedded Policies(BEEP)的系统旨在根据应用程序所有者提供的策略限制浏览器级别的脚本包含。与BEEP相似,Oda等。提出了SOMA,它将BEEP的思想从脚本扩展到其他Web资源。Stamm等人提出了这些想法。谁发布了最初的CSP论文,称为“Reining in the Web with Content Security Policy”。之后,CSP被几家浏览器厂商和标准化委员会选中。2011年,Firefox 以及Chromium 发布第一个实验原型。随后,CSP的几个迭代已经标准化并发布。

最初,CSP受到了很多关注,许多网站开始尝试使用它。但是,由于CSP需要大规模更改,因此采用率仍然很小。 2014年,Weissbacher等人。发表了关于采用CSP的第一项研究。在他们的研究中,他们发现前100个网页中只有1%使用了CSP。为了探究这种低采用率背后的原因,他们通过将CSP策略部署到三个不同的站点进行了实验

因此,他们发现创建初始策略非常困难,因为安全策略需要对现有应用程序进行大量更改。Doup等人研究了这个问题。他们的系统名为deDacota,采用自动代码重写来外化内联脚本。这反过来又使他们的系统能够自动将CSP策略部署到给定的应用程序。

Kerschbaumer等旨在解决类似的问题。他们观察到许多页面使用了不安全的“unsafe-inline”关键字,以避免重写其应用程序。因此,Kerschbaumer等。创建了一个系统,通过众包学习方法自动生成CSP策略。随着时间的推移,他们的系统学习了多个用户观察到的合法脚本,并确保只有这些合法脚本通过脚本哈希在策略中列入白名单。

约翰斯研究了CSP中的另一个问题。在他的论文中,他解决了由动态生成的脚本引起的安全问题。为了应对类似JSONP的端点所施加的威胁,他建议不要根据脚本的来源将脚本列入白名单,而是根据校验和将脚本列入白名单;即脚本的哈希值。但是,这种方法仅适用于静态文件,而不适用于JSONP等动态文件。因此,他提出了一种脚本模板机制,允许开发人员将动态数据值与静态代码分开。通过这种方式,可以为其静态部分计算脚本的哈希值,同时它仍然能够包含动态数据值。

Hausknecht等人的另一篇论文。调查浏览器扩展和CSP之间的紧张关系。作者对Chrome网上商店的浏览器扩展进行了大规模研究,发现许多扩展程序都篡改了网页的CSP。因此,他们提出了一种认可机制,允许扩展程序在更改安全策略之前请求网页获得许可。

在第4节中,我们提出了一种编写CSP策略的新方法。我们建议使用脚本nonce而不是白名单。之前已经提出使用随机数来防止XSS的想法。第一篇论文提出了一个名为Noncespaces的系统。

Noncepaces会自动为合法的HTML标记添加随机XML命名空间。如果应用程序中发生注入漏洞,则攻击者无法预测此随机命名空间,因此无法注入有效的脚本标记。

另一个掌握指令集随机化思想的系统是xJs。xJS使用在服务器和浏览器之间共享的密钥对所有合法的JavaScript代码进行异或,并为每个请求刷新。由于浏览器在运行时解密脚本并且攻击者无法知道密钥,因此无法创建有效的漏洞利用负载。

总结

在本文中,我们基于大规模的实证研究,对在实际应用中采用CSP的实际安全性评估进行了评估。

我们对CSP的安全模型进行了深入分析,并确定了几个看似安全的策略没有提供安全性改进的情况。我们调查了超过10亿个主机名采用CSP,并使用Google搜索索引中的26,011个独特政策识别了160万个主机。

不幸的是,这些政策中的大多数本质上都是不安全的。通过自动检查,我们能够证明94.72%的所有策略都可以被具有标记注入错误的攻击者轻易绕过。此外,我们分析了白名单的安全属性。因此,我们发现75.81%的所有政策和41.65%的所有严格政策在其白名单中至少包含一个不安全的主机。这些数字使我们相信白名单在CSP政策中使用是不切实际的。

因此,我们提出了一种新的政策写作方式。我们建议通过基于CSP nonce的方法启用单个脚本,而不是将整个主机列入白名单。

为了简化基于随机数的CSP的采用,我们还提出了“严格动态”关键字。一旦在CSP策略中指定,此关键字使浏览器内的模式能够将nonce继承到动态脚本。

因此,如果使用nonce信任的脚本在运行时创建新脚本,则此新脚本也将被视为合法。

虽然这种技术背离了CSP的传统主机白名单方法,但我们认为可用性的改进足明其广泛采用的合理性。

由于这是一种选择加入机制,因此默认情况下不会降低CSP的保护功能。

我们希望基于随机数的方法和“严格动态”关键字的结合将使开发人员和组织能够真正享受内容安全策略带来的真正安全性。

原文链接

https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/45542.pdf