瀏覽器安全策略說之內(nèi)容安全策略CSP
前言
2013年11月Veracode給出的報(bào)告指出,全球前1000000網(wǎng)站中僅有269個網(wǎng)站使用了W3C規(guī)范的CSP策略頭Content-Security-Policy。而在2014年2月ZoomEye給出的測試報(bào)告中,國內(nèi)排名前7000的域名沒有使用CSP,國內(nèi)1千萬的域名(含子域名)中僅發(fā)現(xiàn)7個使用了CSP策略,其中還有3個網(wǎng)站CSP語法使用錯誤。
如果說CSP是一個偉大的安全策略,為何全球范圍內(nèi)網(wǎng)站使用率如此之低?是CSP自身的設(shè)計(jì)存在問題,還是網(wǎng)站管理員們沒有去充分了解和利用它。CSP到底是一個什么樣的安全策略,是像人們普遍說的它是XSS攻擊的終結(jié)者嗎?
帶著以上的疑問,本文將從CSP的概念、發(fā)展時間軸、語法使用、如何正確部署CSP、CSP的自有特性、如何利用CSP產(chǎn)生攻擊報(bào)告、CSP當(dāng)前使用率、Bypass CSP等眾多方面,來給大家全面介紹CSP這個偉大而又被忽視的安全策略。
一 CSP概念
內(nèi)容安全策略(Content Security Policy,簡稱CSP)是一種以可信白名單作機(jī)制,來限制網(wǎng)站中是否可以包含某來源內(nèi)容。默認(rèn)配置下不允許執(zhí)行內(nèi)聯(lián)代碼
(<script>塊內(nèi)容,內(nèi)聯(lián)事件,內(nèi)聯(lián)樣式)
以及禁止執(zhí)行
eval() , newFunction() , setTimeout([string], ...) 和setInterval([string], ...) 。
二 CSP發(fā)展時間軸
毋容置疑CSP是一個偉大的策略,但CSP從最初設(shè)計(jì)到被W3C認(rèn)可制定成通用標(biāo)準(zhǔn),卻經(jīng)歷了一個漫長而曲折的過程。
1.CSP模型首次被提出
這要從2007年說起,當(dāng)時XSS攻擊已經(jīng)在OWASP TOP10攻擊中排名第一位,CSP的最初的設(shè)想就在這一年被Mozilla項(xiàng)目組的Gervase Markham和WEB安全界大牛Robert Hansen ‘rsnake’兩人共同提出的。
2.瀏覽器首次使用CSP
2011年3月Firefox 4.0發(fā)布,首次把CSP當(dāng)作一種正式的安全策略規(guī)范使用到瀏覽器中。當(dāng)時火狐使用的是自己定義的X-Content-Security-Policy頭。單從CSP推廣上來看,F(xiàn)irefox4.0的發(fā)布是劃時代的,雖然此時的CSP只是Firefox自己定義的一個內(nèi)部標(biāo)準(zhǔn)。但在此之后,CSP的概念被全球迅速推廣。
3.Chrome使用CSP
隨后在2011年9月,谷歌在Chrome瀏覽器14.0版本發(fā)布時加入CSP,而Chrome瀏覽器使用的也是自己的CSP標(biāo)準(zhǔn),它使用X-Webkit-CSP頭進(jìn)行對CSP的解析,這個頭從字面上更能看出來Chrome瀏覽器使用的是Webkit內(nèi)核。此時世界主流的2大瀏覽器Chrome、Firefox都已經(jīng)支持了CSP。
4.W3C起草CSP標(biāo)準(zhǔn)
作為標(biāo)準(zhǔn)發(fā)布的W3C組織順其自然在2011年11月在官網(wǎng)上發(fā)布了CSP1.0草案。W3C的CSP1.0草案的語法和Firefox和Chrome中截然不同,隨著時間的推移1年后,W3C的CSP1.0草案已經(jīng)到了推選階段,基本可以正式發(fā)布。
5.全面支持W3C標(biāo)準(zhǔn)的CSP
在2012年2月Chrome25版本發(fā)布時,宣布支持W3C標(biāo)準(zhǔn)的CSP1.0。2013年6月Firefox宣布在23版本中全面支持W3C的CSP1.0標(biāo)準(zhǔn)。同樣是在2013年6月,W3C發(fā)布CSP1.1標(biāo)準(zhǔn),里面又加入了不少語法,現(xiàn)在大多瀏覽器還都不支持。IE10中開始支持CSP中的’sandbox’語法,其他語法暫不支持。
目前CSP各個瀏覽器支持情況可以去http://caniuse.com/#feat=contentsecuritypolicy查看
#p#
三 CSP語法
CSP1.0指令
CSP1.1新增指令
CSP語法
#p#
四 CSP默認(rèn)特性
A.阻止內(nèi)聯(lián)代碼執(zhí)行
CSP除了使用白名單機(jī)制外,默認(rèn)配置下阻止內(nèi)聯(lián)代碼執(zhí)行是防止內(nèi)容注入的最大安全保障。
這里的內(nèi)聯(lián)代碼包括:<script>塊內(nèi)容,內(nèi)聯(lián)事件,內(nèi)聯(lián)樣式
1. 1 script代碼,
<script>……<scritp>
對于script塊內(nèi)容是完全不能執(zhí)行的。例如:
<script>getyourcookie()</script>
2. 2內(nèi)聯(lián)事件。
<a href="" onclick="handleClick();"></a>
<a href="javascript:handleClick();"></a>
3. 3 內(nèi)聯(lián)樣式
<div class="tab" style="display:none"></div>
雖然CSP中已經(jīng)對script-src和style-src提供了使用”unsafe-inline”指令來開啟執(zhí)行內(nèi)聯(lián)代碼,但為了安全起見還是慎用”unsafe-inline”。
B.EVAL相關(guān)功能被禁用
用戶輸入字符串,然后經(jīng)過eval()等函數(shù)轉(zhuǎn)義進(jìn)而被當(dāng)作腳本去執(zhí)行。這樣的攻擊方式比較常見。于是乎CSP默認(rèn)配置下,eval() , newFunction() , setTimeout([string], ...) 和setInterval([string], ...) 都被禁止運(yùn)行。
比如:
alert(eval("foo.bar.baz")); window.setTimeout("alert('hi')", 10); window.setInterval("alert('hi')", 10); new Function("return foo.bar.baz");
如果想執(zhí)行可以把字符串轉(zhuǎn)換為內(nèi)聯(lián)函數(shù)去執(zhí)行。
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”去開啟執(zhí)行eval()等函數(shù),但強(qiáng)烈不建議去使用”unsafe-eval”這個指令。#p#
五 CSP例子
例子1
網(wǎng)站管理員想要所有的內(nèi)容均來自網(wǎng)站自己的域,不包括子域
Content-Security-Policy: default-src 'self‘
例子2
網(wǎng)站管理員想要所有的內(nèi)容來自網(wǎng)站自己的域,還有其他子域的內(nèi)容
Content-Security-Policy: default-src 'self' *.mydomain.com
例子3
網(wǎng)站管理員想要網(wǎng)站接受信任任意域的圖像,指定域的音頻視頻和指定域的腳本。
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
在這條策略中,默認(rèn)情況下,網(wǎng)站只允許加載自己域的內(nèi)容。
但也有例外:
img-src * 使用*通配符可以加載任意域的圖片。
media-src media1.com media2.com 視頻音頻只允許加載這兩個域的
script-src userscripts.example.com 腳本只能加載
userscripts.example.com域的
例子4
網(wǎng)站管理員確保在線銀行所有內(nèi)容都通過SSL加載,確保信息不會被截獲。
Content-Security-Policy: default-src https://onlinebanking.jumbobank.com
例子5
看github.com的真實(shí)CSP例子。Github允許加載任何域的內(nèi)容,但只能加載指定域的腳本,只能加載指定域的樣式并可以執(zhí)行內(nèi)聯(lián)樣式,只能通過SSL加載指定域的flash插件。
Content-Security-Policy:default-src *;
script-src 'self'
https://github.global.ssl.fastly.net https://ssl.google-analytics.com
https://collector-cdn.github.com https://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編寫,可以協(xié)助和幫助網(wǎng)站管理員編寫出適合自己站點(diǎn)的CSP。http://cspisawesome.com/
#p#
六 CSP的錯誤使用
CSP的語法和指令并不復(fù)雜,但如果沒有充分了解網(wǎng)站業(yè)務(wù)和安全需求,錯誤的使用CSP則會適得其反。
(1)筆者在2013年底訪問http://www.grosshandel-hahn.de/,發(fā)現(xiàn)CSP策略明顯使用錯誤。
可以看到使用X-Content-Security-Policy-Report-Only。此頭的意思是讓瀏覽器只匯報(bào)日志,不阻止任何內(nèi)容。但這條策略里卻沒有給出接收信息日志的地址。
(2)Content-Security-Policy: default-src https:; frame-src test.com;。這個策略方案是有問題的,此頭限制https以外的所有資源,但又允許iframe通過http進(jìn)行加載。現(xiàn)實(shí)中,這樣的場景應(yīng)該很難出現(xiàn)。
七 CSP分析報(bào)告
對于網(wǎng)站管理員來說CSP的一個強(qiáng)大功能是它可以產(chǎn)生試圖攻擊你網(wǎng)站的分析報(bào)告。你可以用report-uri指令使瀏覽器發(fā)送HTTP POST請求把攻擊報(bào)告以JSON格式傳送到你指定的地址。接下來給大家介紹你的站點(diǎn)如何配置來接收攻擊報(bào)告。
1. 啟用報(bào)告
默認(rèn)情況下,違規(guī)報(bào)告不會發(fā)送。為了能使用違規(guī)報(bào)告,你必須使用report-uri指令,并至少提供一個接收地址。
Content-Security-Policy: default-src self; report-uri
http://reportcollector.example.com/collector.cgi
如果想讓瀏覽器只匯報(bào)報(bào)告,不阻止任何內(nèi)容,可以改用Content-Security-Policy-Report-Only頭。
2.違規(guī)報(bào)告語法
該報(bào)告JSON對象包含以下數(shù)據(jù):
blocked-uri:被阻止的違規(guī)資源
document-uri:攔截違規(guī)行為發(fā)生的頁面
original-policy:Content-Security-Policy頭策略的所有內(nèi)容
referrer:頁面的referrer
status-code:HTTP響應(yīng)狀態(tài)
violated-directive:違規(guī)的指令
3.違規(guī)報(bào)告例子
http://example.com/signup.html 中CSP 規(guī)定只能加載cdn.example.com的CSS樣式。
Content-Security-Policy: default-src 'none'; style-src
cdn.example.com; report-uri /test/csp-report.php
signup.html中的代碼類似與這樣:
- <!DOCTYPE html>
- <html>
- <head>
- <title>Sign Up</title>
- <link rel="stylesheet" href="css/style.css">
- </head>
- <body>
- ... Content ...
- </body>
- </html>
你能從上面的代碼找出錯誤嗎?策略是只允許加載cdn.example.com中的CSS樣式。但signup.html試圖加載自己域的style.css樣式。這樣違反了策略,瀏覽器會向
http://example.com/test/csp-report.php 發(fā)送POST請求提交報(bào)告,發(fā)送格式為JSON格式。
- {
- "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給出了詳細(xì)的阻斷地址http://example.com/css/style.css,但也并不是每次都是這樣。比如試圖從http://anothercdn.example.com/stylesheet.css 加載CSS樣式時,瀏覽器將不會傳送完整的路徑,只會給出http://anothercdn.example.com/這個地址。這樣做是為了防止泄漏跨域的敏感信息。
服務(wù)端csp-report.php代碼可以這樣寫:
- <?php
- $file = fopen('csp-report.txt', 'a');
- $json = file_get_contents('php://input');
- $csp = json_decode($json, true);
- foreach ($csp['csp-report'] as $key => $val) {
- fwrite($file, $key . ': ' . $val . "
- ");
- }
- fwrite($file, 'End of report.' . "
- ");
- fclose($file);
- ?>
#p#
八 CSP的使用率統(tǒng)計(jì)
CSP的全球范圍使用率非常低,而且增加的也非常緩慢。根據(jù)Veracode在2013年11月給出的報(bào)告指出,全球前1000000網(wǎng)站中僅有269個網(wǎng)站使用了W3C規(guī)范的CSP策略頭Content-Security-Policy。584個網(wǎng)站在使用X-Content-Security-Policy策略頭和487個網(wǎng)站在使用X-Webkit-CSP策略頭,這兩個協(xié)議頭已經(jīng)被廢棄,但還沒有被禁用。
而使用Content-Security-Policy-Report-Only進(jìn)行單獨(dú)接收攻擊報(bào)告的網(wǎng)站只有24個。而統(tǒng)計(jì)中也指出,發(fā)現(xiàn)大量網(wǎng)站使用unsafe-inline這個指令,分析其原因可能是由于開發(fā)人員很難在頁面中徹底消除內(nèi)聯(lián)腳本,這很讓人失望,所有只能要求制定的CSP策略更加嚴(yán)謹(jǐn)。
http://blog.veracode.com/2013/11/security-headers-on-the-top-1000000-websites-november-2013-report/
對于國內(nèi)網(wǎng)站使用CSP的情況,筆者委托ZoomEye對此進(jìn)行了統(tǒng)計(jì)。2014年2月發(fā)來的統(tǒng)計(jì)結(jié)果在非常不樂觀。根據(jù)ZoomEye的統(tǒng)計(jì):國內(nèi)排名前7000的域名沒有使用CSP,國內(nèi)1千萬的域名(含子域名)中發(fā)現(xiàn)7個使用了CSP策略,其中還有3個網(wǎng)站CSP語法使用錯誤。7個網(wǎng)站中3個網(wǎng)站是知乎,知乎網(wǎng)站值得表揚(yáng)。
列表如下:
www.zhihu.com
www.zhi.hu
zhimg.com
www.applysquare.com
www.pipapai.com CSP語法錯誤
www.icyprus.cn CSP語法錯誤
www.uyitec.cn CSP語法錯誤
在網(wǎng)站安全防御方面,我們還要有很長的路要走。雖然CSP安全策略頭只是網(wǎng)站安全整體防御中的一小部分,但合理的利用還是可以起到很好的防護(hù)作用。然而在我們分析的百萬網(wǎng)站中,CSP的使用率是極其的低,從這一點(diǎn)來說CSP在國內(nèi)就應(yīng)該廣泛的給網(wǎng)站管理員進(jìn)行科普。#p#
九 CSP Bypass
一個安全策略從誕生開始將會時不時的有一個叫“Bypass”的小伙伴跟隨左右。而從辯證角度來講,多加載一種安全策略,就多了一種Bypass的維度。一旦Bypass出現(xiàn),就意味著將有一種設(shè)計(jì)者沒有考慮到的方法或技巧,將破壞策略的原有規(guī)則。
CSP也亦是如此,在一次次被繞過然后在一次次修復(fù)過程中,來完善自己的語法和指令。
1.bypass AngularJS系列繞過
AngularJS是為數(shù)不多的支持CSP模式的MVC框架,在早起版本中可以構(gòu)造多種方式繞過CSP防御。
CSP Bypasses with AngularJS 1.0.8 and 1.1.5
例如:XSS via Click & Hover (ng-click & ng-mouseover attribute)
- <?php
- header('X-Content-Security-Policy: default-src 'self' ajax.googleapis.com');
- header('Content-Security-Policy: default-src 'self' ajax.googleapis.com');
- header('X-Webkit-CSP: default-src 'self' ajax.googleapis.com');
- header('Set-Cookie: abc=123');
- ?><!doctype html>
- <html ng-app ng-csp>
- <head>
- <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
- </head>
- <body ng-click="$event.view.alert(1)">
- Click me
- <h1 ng-mouseover="$event.target.ownerDocument.defaultView.alert(2)">Hover me</h1>
- </body>
更多的可以看https://code.google.com/p/mustache-security/wiki/AngularJS
2.策略優(yōu)先級繞過
在瀏覽器的保護(hù)策略中,有很多是重復(fù)的。比如A策略可以抵御C攻擊,B策略也可以抵御C攻擊。此處的抵御可以是阻斷也可以是放行。于是當(dāng)AB同時作用于C攻擊上時,Bypass就可能發(fā)生。
(1)Iframe sandbox 和 CSP sandbox
當(dāng)iframe sandbox允許執(zhí)行JS,而CSP不允許執(zhí)行JS,問題就發(fā)生了,CSP就被bypass了。
- //evil.com
- <iframe sandbox="allow-scripts" src="//victim.com/csp.html">
- //victim.com
- <?php
- header('X-Content-Security-Policy: default-src 'self'');
- header('Content-Security-Policy: default-src 'self'');
- header('X-Webkit-CSP: default-src 'self'');
- header('Set-Cookie: abc=123');
- ?><!doctype html>
- <body onclick="alert(1)">
- Click me
- </body>
詳細(xì)的討論可以看這里:https://bugzilla.mozilla.org/show_bug.cgi?id=886164
(2)XSS Auditor和CSP
關(guān)于XSS Auditor和CSP,這里筆者想進(jìn)行一次更開放式的討論。以Chrome中測試為例,當(dāng)XSS Auditor和CSP同時作用到一段JS代碼上,會有怎樣一個效果呢。比如XSS Auditor設(shè)置的是阻斷,CSP里設(shè)置unsafe-inline放行,結(jié)果還是被阻斷。這是由于瀏覽器解析JS腳本的時候先使用了XSS auditor這層安全防御策略,所以CSP中的unsafe-inline這個指令并沒有起作用,從廣義的角度來看,CSP中的策略被Bypass了。瀏覽器的策略中,類似與這樣的情況還有很多。比如下面介紹的這個。
(3) X-Frame-Options和CSP frame
當(dāng)a.com設(shè)置X-Frame-Options:deny,b.com設(shè)置CSP frame-src a.com,那么b.com是否可以iframe a.com呢。測試中發(fā)現(xiàn)a.com還是不能被b.com包含的。你可以認(rèn)為瀏覽器解析中,X-Frame-Options優(yōu)先級大于CSP frame。#p#
十 CSP總結(jié)
1.充分了解CSP安全策略的語法和指令,并最大程度的合理的去利用和部署這些策略,努力把安全策略發(fā)揮到極致,使其最終把危害降低到最低。
2.CSP并不能消除內(nèi)容注入攻擊,但可以有效的檢測并緩解跨站攻擊和內(nèi)容注入攻擊帶來的危害。
3.CSP不是做為防御內(nèi)容注入(如XSS)的第一道防線而設(shè)計(jì),而最適合部署在縱深防御體系中。
4.關(guān)于為什么CSP的使用率如此之低。究其原因,CSP雖然提供了強(qiáng)大的安全保護(hù),但是他也造成了如下問題:Eval及相關(guān)函數(shù)被禁用、內(nèi)嵌的JavaScript代碼將不會執(zhí)行、只能通過白名單來加載遠(yuǎn)程腳本。這些問題阻礙CSP的普及,如果要使用CSP技術(shù)保護(hù)自己的網(wǎng)站,開發(fā)者就不得不花費(fèi)大量時間分離內(nèi)聯(lián)的JavaScript代碼和做一些調(diào)整。
5.沒有被繞過的策略不是好的策略,而從辯證角度來講,多加載一種安全策略,就多了一種Bypass的維度。在安全領(lǐng)域“Bypass”是一個曼妙而鬼魅的名字。
6.應(yīng)該把CSP安全策略視為是一把可以直插心臟的鋒利的尖刀,而不是一根電線桿子杵在那。
十一 參考
1. http://www.w3.org/TR/CSP11/
2. http://www.w3.org/TR/CSP/
3. http://www.html5rocks.com/en/tutorials/security/content-security-policy/
4. http://ruxcon.org.au/assets/slides/CSP-kuza55.pptx
5. https://code.google.com/p/mustache-security/wiki/AngularJS
6. http://content-security-policy.com/
7. https://github.com/blog/1477-content-security-policy
8. http://cspisawesome.com/
9. https://developer.mozilla.org/en-US/docs/Security/CSP/Using_Content_Security_Policy
10. http://benvinegar.github.io/csp-talk-2013/#1
11. http://caniuse.com/#feat=contentsecuritypolicy
12. https://www.imququ.com/post/content-security-policy-reference.html
13. http://docs.angularjs.org/api/ng.directive:ngCsp
14. https://developer.mozilla.org/en-US/docs/Security/CSP/Using_CSP_violation_reports
15. http://stackoverflow.com/questions/14629534/json-post-in-php-csp-report
16. http://mathiasbynens.be/notes/csp-reports
17. http://www.madirish.net/556
18. http://www.veracode.com/blog/2013/11/security-headers-on-the-top-1000000-websites-november-2013-report/
19. https://github.com/google/CSP-Validator
20. http://www.benmarshall.me/content-security-policy/
21. http://www.slideshare.net/x00mario/jsmvcomfg-to-sternly-look-at-javascript-mvc-and-templating-frameworks
22. http://trends.builtwith.com/javascript/Angular-JS
23. http://developer.chrome.com/extensions/contentSecurityPolicy
24. http://cs.ucsb.edu/~adoupe/static/dedacota-ccs2013.pdf