04月18日 綜合消息:
前言
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這個偉大而又被忽視的安全策略。
一 CSP概念
內容安全策略(Content Security Policy,簡稱CSP)是一種以可信白名單作機制,來限制網站中是否可以包含某來源內容。默認配置下不允許執行內聯代碼(<script>塊內容,內聯事件,內聯樣式),以及禁止執行eval() , newFunction() , setTimeout([string], ...) 和setInterval([string], ...) 。
二 CSP發展時間軸
毋容置疑CSP是一個偉大的策略,但CSP從最初設計到被W3C認可制定成通用標準,卻經歷了一個漫長而曲折的過程。
1.CSP模型首次被提出
這要從2007年說起,當時XSS攻擊已經在OWASP TOP10攻擊中排名第一位,CSP的最初的設想就在這一年被Mozilla項目組的Gervase Markham和WEB安全界大牛Robert Hansen ‘rsnake’兩人共同提出的。
2.瀏覽器首次使用CSP
2011年3月Firefox 4.0發布,首次把CSP當作一種正式的安全策略規范使用到瀏覽器中。當時火狐使用的是自己定義的X-Content-Security-Policy頭。單從CSP推廣上來看,Firefox4.0的發布是劃時代的,雖然此時的CSP只是Firefox自己定義的一個內部標準。但在此之后,CSP的概念被全球迅速推廣。
3.Chrome使用CSP
隨后在2011年9月,谷歌在Chrome瀏覽器14.0版本發布時加入CSP,而Chrome瀏覽器使用的也是自己的CSP標準,它使用X-Webkit-CSP頭進行對CSP的解析,這個頭從字面上更能看出來Chrome瀏覽器使用的是Webkit內核。此時世界主流的2大瀏覽器Chrome、Firefox都已經支持了CSP。
4.W3C起草CSP標準
作為標準發布的W3C組織順其自然在2011年11月在官網上發布了CSP1.0草案。W3C的CSP1.0草案的語法和Firefox和Chrome中截然不同,隨著時間的推移1年后,W3C的CSP1.0草案已經到了推選階段,基本可以正式發布。
5.全面支持W3C標準的CSP
在2012年2月Chrome25版本發布時,宣布支持W3C標準的CSP1.0。2013年6月Firefox宣布在23版本中全面支持W3C的CSP1.0標準。同樣是在2013年6月,W3C發布CSP1.1標準,里面又加入了不少語法,現在大多瀏覽器還都不支持。IE10中開始支持CSP中的’sandbox’語法,其他語法暫不支持。
目前CSP各個瀏覽器支持情況可以去http://caniuse.com/#feat=contentsecuritypolicy查看
這里的內聯代碼包括:<script>塊內容,內聯事件,內聯樣式
1. 1 script代碼,<script>……<scritp>
對于<script>塊內容是完全不能執行的。例如:
<script>getyourcookie()</script>
2. 2內聯事件。
<a href="" onclick="handleClick();"></a>
<a href="javascript:handleClick();"></a>
3. 3 內聯樣式
<div class="tab" style="display:none"></div>
雖然CSP中已經對script-src和style-src提供了使用”unsafe-inline”指令來開啟執行內聯代碼,但為了安全起見還是慎用”unsafe-inline”。
B.EVAL相關功能被禁用
用戶輸入字符串,然后經過eval()等函數轉義進而被當作腳本去執行。這樣的攻擊方式比較常見。于是乎CSP默認配置下,eval() , newFunction() , setTimeout([string], ...) 和setInterval([string], ...) 都被禁止運行。
比如:
alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");
如果想執行可以把字符串轉換為內聯函數去執行。
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”這個指令。
五 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.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編寫,可以協助和幫助網站管理員編寫出適合自己站點的CSP。http://cspisawesome.com/
六 CSP的錯誤使用
CSP的語法和指令并不復雜,但如果沒有充分了解網站業務和安全需求,錯誤的使用CSP則會適得其反。
(1)筆者在2013年底訪問http://www.grosshandel-hahn.de/,發現CSP策略明顯使用錯誤。
可以看到使用X-Content-Security-Policy-Report-Only。此頭的意思是讓瀏覽器只匯報日志,不阻止任何內容。但這條策略里卻沒有給出接收信息日志的地址。
七 CSP分析報告
對于網站管理員來說CSP的一個強大功能是它可以產生試圖攻擊你網站的分析報告。你可以用report-uri指令使瀏覽器發送HTTP POST請求把攻擊報告以JSON格式傳送到你指定的地址。接下來給大家介紹你的站點如何配置來接收攻擊報告。
1. 啟用報告
默認情況下,違規報告不會發送。為了能使用違規報告,你必須使用report-uri指令,并至少提供一個接收地址。
Content-Security-Policy: default-src self; report-uri
http://reportcollector.example.com/collector.cgi
如果想讓瀏覽器只匯報報告,不阻止任何內容,可以改用Content-Security-Policy-Report-Only頭。
2.違規報告語法
該報告JSON對象包含以下數據:
blocked-uri:被阻止的違規資源
document-uri:攔截違規行為發生的頁面
original-policy:Content-Security-Policy頭策略的所有內容
referrer:頁面的referrer
status-code:HTTP響應狀態
violated-directive:違規的指令
3.違規報告例子
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中的代碼類似與這樣:
<!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 發送POST請求提交報告,發送格式為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給出了詳細的阻斷地址http://example.com/css/style.css,但也并不是每次都是這樣。比如試圖從http://anothercdn.example.com/stylesheet.css 加載CSS樣式時,瀏覽器將不會傳送完整的路徑,只會給出http://anothercdn.example.com/這個地址。這樣做是為了防止泄漏跨域的敏感信息。
服務端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);
?>
八 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策略更加嚴謹。
對于國內網站使用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.cn CSP語法錯誤
www.uyitec.cn CSP語法錯誤
在網站安全防御方面,我們還要有很長的路要走。雖然CSP安全策略頭只是網站安全整體防御中的一小部分,但合理的利用還是可以起到很好的防護作用。然而在我們分析的百萬網站中,CSP的使用率是極其的低,從這一點來說CSP在國內就應該廣泛的給網站管理員進行科普。
九 CSP Bypass
一個安全策略從誕生開始將會時不時的有一個叫“Bypass”的小伙伴跟隨左右。而從辯證角度來講,多加載一種安全策略,就多了一種Bypass的維度。一旦Bypass出現,就意味著將有一種設計者沒有考慮到的方法或技巧,將破壞策略的原有規則。
CSP也亦是如此,在一次次被繞過然后在一次次修復過程中,來完善自己的語法和指令。
1.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
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.策略優先級繞過
在瀏覽器的保護策略中,有很多是重復的。比如A策略可以抵御C攻擊,B策略也可以抵御C攻擊。此處的抵御可以是阻斷也可以是放行。于是當AB同時作用于C攻擊上時,Bypass就可能發生。
(1)Iframe sandbox 和 CSP sandbox
當iframe sandbox允許執行JS,而CSP不允許執行JS,問題就發生了,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>
詳細的討論可以看這里:https://bugzilla.mozilla.org/show_bug.cgi?id=886164
(2)XSS Auditor和CSP
關于XSS Auditor和CSP,這里筆者想進行一次更開放式的討論。以Chrome中測試為例,當XSS Auditor和CSP同時作用到一段JS代碼上,會有怎樣一個效果呢。比如XSS Auditor設置的是阻斷,CSP里設置unsafe-inline放行,結果還是被阻斷。這是由于瀏覽器解析JS腳本的時候先使用了XSS auditor這層安全防御策略,所以CSP中的unsafe-inline這個指令并沒有起作用,從廣義的角度來看,CSP中的策略被Bypass了。瀏覽器的策略中,類似與這樣的情況還有很多。比如下面介紹的這個。
(3) X-Frame-Options和CSP frame
當a.com設置X-Frame-Options:deny,b.com設置CSP frame-src a.com,那么b.com是否可以iframe a.com呢。測試中發現a.com還是不能被b.com包含的。你可以認為瀏覽器解析中,X-Frame-Options優先級大于CSP frame。
十 CSP總結
1.充分了解CSP安全策略的語法和指令,并最大程度的合理的去利用和部署這些策略,努力把安全策略發揮到極致,使其最終把危害降低到最低。
2.CSP并不能消除內容注入攻擊,但可以有效的檢測并緩解跨站攻擊和內容注入攻擊帶來的危害。
3.CSP不是做為防御內容注入(如XSS)的第一道防線而設計,而最適合部署在縱深防御體系中。
4.關于為什么CSP的使用率如此之低。究其原因,CSP雖然提供了強大的安全保護,但是他也造成了如下問題:Eval及相關函數被禁用、內嵌的JavaScript代碼將不會執行、只能通過白名單來加載遠程腳本。這些問題阻礙CSP的普及,如果要使用CSP技術保護自己的網站,開發者就不得不花費大量時間分離內聯的JavaScript代碼和做一些調整。
5.沒有被繞過的策略不是好的策略,而從辯證角度來講,多加載一種安全策略,就多了一種Bypass的維度。在安全領域“Bypass”是一個曼妙而鬼魅的名字。
6.應該把CSP安全策略視為是一把可以直插心臟的鋒利的尖刀,而不是一根電線桿子杵在那。