浏览器安全策略说之内容安全策略CSP

天融信阿尔法实验室 · 2014/04/17 14:50

目录
0x00前言 0x01CSP概念 0x02CSP发展时间轴 0x03CSP语法 0x04CSP默认特性 0x05CSP例子 0x06CSP的错误使用 0x07CSP分析报告 0x08CSP的使用率统计 0x09CSP Bypass 0x0aCSP总结 0x0b参考 复制代码

0x00 前言 一直说要去写个浏览器安全策略系列,10篇安全策略的内容虽早已成竹在胸,但写出来却要花费好多时间。CSP这篇已于一个月前写出来,而后筹备Blog上线用了一段时间,不容易。FirstBlood,第一篇文章就献给阿尔法实验室和浏览器中一个伟大而又被忽略的安全策略CSP吧。好酒值得细细去品,好的安全策略也一样。废话少说,下面正式进入文章主题。
2013年11月Veracode给出的报告指出,全球前1000000网站中仅有269个网站使用了W3C规范的CSP策略头Content-Security-Policy。而在2014年2月ZoomEye给出的测试报告中,国内排名前7000的域名没有使用CSP,国内1千万的域名(含子域名)中仅发现7个使用了CSP策略,其中还有3个网站CSP语法使用错误。
如果说CSP是一个伟大的安全策略,为何全球范围内网站使用率如此之低?是CSP自身的设计存在问题,还是网站管理员们没有去充分了解和利用它。CSP到底是一个什么样的安全策略,是像人们普遍说的它是XSS攻击的终结者吗?
带着以上的疑问,本文将从CSP的概念、发展时间轴、语法使用、如何正确部署CSP、CSP的自有特性、如何利用CSP产生攻击报告、CSP当前使用率、Bypass CSP等众多方面,来给大家全面介绍CSP这个伟大而又被忽视的安全策略。
0x01 CSP概念 内容安全策略(Content Security Policy,简称CSP)是一种以可信白名单作机制,来限制网站中是否可以包含某来源内容。默认配置下不允许执行内联代码( 复制代码
(2) 内联事件
#!html复制代码

(3) 内联样式
#!html复制代码

虽然CSP中已经对script-src和style-src提供了使用”unsafe-inline”指令来开启执行内联代码,但为了安全起见还是慎用”unsafe-inline”。
EVAL相关功能被禁用
用户输入字符串,然后经过eval()等函数转义进而被当作脚本去执行。这样的攻击方式比较常见。于是乎CSP默认配置下,eval() , newFunction() , setTimeout([string], …) 和setInterval([string], …)都被禁止运行。
比如:
#!js alert(eval("foo.bar.baz")); window.setTimeout("alert('hi')", 10); window.setInterval("alert('hi')", 10); new Function("return foo.bar.baz"); 复制代码

如果想执行可以把字符串转换为内联函数去执行。
#!html alert(foo && foo.bar && foo.bar.baz); window.setTimeout(function() { alert('hi'); }, 10); window.setInterval(function() { alert('hi'); }, 10); function() { return foo && foo.bar && foo.bar.baz }; 复制代码

同样CSP也提供了”unsafe-eval”去开启执行eval()等函数,但强烈不建议去使用”unsafe-eval”这个指令。
0x05 CSP例子 例子1
网站管理员想要所有的内容均来自网站自己的域,不包括子域。
Content-Security-Policy: default-src 'self' 复制代码

例子2
网站管理员想要所有的内容来自网站自己的域,还有其他子域的内容。
Content-Security-Policy: default-src 'self' *.mydomain.com 复制代码

例子3
网站管理员想要网站接受信任任意域的图像,指定域的音频视频和指定域的脚本。
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com 复制代码

在这条策略中,默认情况下,网站只允许加载自己域的内容。但也有例外:
img-src * 使用*通配符可以加载任意域的图片。 media-src media1.com media2.com 视频音频只允许加载这两个域的 script-src userscripts.example.com 脚本只能加载userscripts.example.com域的 复制代码

例子4
网站管理员确保在线银行所有内容都通过SSL加载,确保信息不会被截获。
Content-Security-Policy: default-src https://onlinebanking.jumbobank.com 复制代码

例子5
看github.com的真实CSP例子。Github允许加载任何域的内容,但只能加载指定域的脚本,只能加载指定域的样式并可以执行内联样式,只能通过SSL加载指定域的flash插件。
Content-Security-Policy:default-src *; script-src 'self' https://github.global.ssl.fastly.nethttps://ssl.google-analytics.com https://collector-cdn.github.comhttps://embed.github.com https://raw.github.com; style-src 'self' 'unsafe-inline' https://github.global.ssl.fastly.net; object-src https://github.global.ssl.fastly.net 复制代码

在线CSP编写
在线CSP编写,可以协助和帮助网站管理员编写出适合自己站点的CSP。http://cspisawesome.com/

0x06 CSP的错误使用 CSP的语法和指令并不复杂,但如果没有充分了解网站业务和安全需求,错误的使用CSP则会适得其反。
(1)我在2013年底访问http://www.grosshandel-hahn.de/,发现CSP策略明显使用错误。

可以看到使用X-Content-Security-Policy-Report-Only。此头的意思是让浏览器只汇报日志,不阻止任何内容。但这条策略里却没有给出接收信息日志的地址。
(2)Content-Security-Policy: default-src https:; frame-src test.com; 。这个策略方案是有问题的,此头限制https以外的所有资源,但又允许iframe通过http进行加载。现实中,这样的场景应该很难出现。
0x07 CSP分析报告 对于网站管理员来说CSP的一个强大功能是它可以产生试图攻击你网站的分析报告。你可以用report-uri指令使浏览器发送HTTP POST请求把攻击报告以JSON格式传送到你指定的地址。接下来给大家介绍你的站点如何配置来接收攻击报告。
启用报告
默认情况下,违规报告不会发送。为了能使用违规报告,你必须使用report-uri指令,并至少提供一个接收地址。
Content-Security-Policy: default-src self; report-uri http://reportcollector.example.com/collector.cgi 复制代码

如果想让浏览器只汇报报告,不阻止任何内容,可以改用Content-Security-Policy-Report-Only头。
违规报告语法
该报告JSON对象包含以下数据:
blocked-uri:被阻止的违规资源 document-uri:拦截违规行为发生的页面 original-policy:Content-Security-Policy头策略的所有内容 referrer:页面的referrer status-code:HTTP响应状态 violated-directive:违规的指令 复制代码

违规报告例子
http://example.com/signup.html 中CSP 规定只能加载cdn.example.com的CSS样式。
Content-Security-Policy: default-src 'none'; style-src cdn.example.com; report-uri /test/csp-report.php 复制代码

signup.html中的代码类似与这样:
#!html Sign Up ... Content ... 复制代码

你能从上面的代码找出错误吗?策略是只允许加载cdn.example.com中的CSS样式。但signup.html试图加载自己域的style.css样式。这样违反了策略,浏览器会向http://example.com/test/csp-report.php 发送POST请求提交报告,发送格式为JSON格式。
#!js { "csp-report": { "document-uri": "http://example.com/signup.html", "referrer": "", "blocked-uri": "http://example.com/css/style.css", "violated-directive": "style-src cdn.example.com", "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports", } } 复制代码

你从上面可以看到blocked-uri给出了详细的阻断地址http://example.com/css/style.css,但也并不是每次都是这样。比如试图从http://anothercdn.example.com/stylesheet.css 加载CSS样式时,浏览器将不会传送完整的路径,只会给出http://anothercdn.example.com/这个地址。这样做是为了防止泄漏跨域的敏感信息。
服务端csp-report.php代码可以这样写:
#!php $val) { fwrite($file, $key . ': ' . $val . " "); } fwrite($file, 'End of report.' . " "); fclose($file); ?> 复制代码

0x08 CSP的使用率统计 CSP的全球范围使用率非常低,而且增加的也非常缓慢。根据Veracode在2013年11月给出的报告指出,全球前1000000网站中仅有269个网站使用了W3C规范的CSP 策略头Content-Security-Policy。584个网站在使用X-Content-Security-Policy策略头和487个网站在使用X-Webkit-CSP策略头,这两个协议头已经被废弃,但还没有被禁用。
而使用Content-Security-Policy-Report-Only进行单独接收攻击报告的网站只有24个。而统计中也指出,发现大量网站使用unsafe-inline这个指令,分析其原因可能是由于开发人员很难在页面中彻底消除内联脚本,这很让人失望,所有只能要求制定的CSP策略更加严谨。

blog.veracode.com/2013/11/sec…
对于国内网站使用CSP的情况,我给余弦打了个招呼,ZoomEye对此进行了统计。2014年2月发来的统计结果在非常不乐观。根据ZoomEye的统计:国内排名前7000的域名没有使用CSP,国内1千万的域名(含子域名)中发现7个使用了CSP策略,其中还有3个网站CSP语法使用错误。7个网站中3个网站是知乎,知乎网站值得表扬。列表如下:
www.zhihu.com www.zhi.hu zhimg.com www.applysquare.com www.pipapai.com CSP语法错误 www.icyprus.cnCSP语法错误 www.uyitec.cnCSP语法错误 复制代码

在网站安全防御方面,我们还要有很长的路要走。虽然CSP安全策略头只是网站安全整体防御中的一小部分,但合理的利用还是可以起到很好的防护作用。然而在我们分析的百万网站中,CSP的使用率是极其的低,从这一点来说CSP在国内就应该广泛的给网站管理员进行科普。
0x09 CSP Bypass 一个安全策略从诞生开始将会时不时的有一个叫“Bypass”的小伙伴跟随左右。而从辩证角度来讲,多加载一种安全策略,就多了一种Bypass的维度。一旦Bypass出现,就意味着将有一种设计者没有考虑到的方法或技巧,将破坏策略的原有规则。
CSP也亦是如此,在一次次被绕过然后在一次次修复过程中,来完善自己的语法和指令。
bypass AngularJS系列绕过
AngularJS是为数不多的支持CSP模式的MVC框架,在早起版本中可以构造多种方式绕过CSP防御。
CSP Bypasses with AngularJS 1.0.8 and 1.1.5
例如:XSS via Click & Hover (ng-click & ng-mouseover attribute)
#!php Click me Hover me 复制代码

更多的可以看code.google.com/p/mustache-…
策略优先级绕过
在浏览器的保护策略中,有很多是重复的。比如A策略可以抵御C攻击,B策略也可以抵御C攻击。此处的抵御可以是阻断也可以是放行。于是当AB同时作用于C攻击上时,Bypass就可能发生。
(1)Iframe sandbox 和 CSP sandbox
当iframe sandbox允许执行JS,而CSP不允许执行JS,问题就发生了,CSP就被bypass了。
#!php //evil.com