瀏覽器安全策略說之內容安全策略CSP

wyzsk發表於2020-08-19
作者: 天融信阿爾法實驗室 · 2014/04/17 14:50

目錄

0x00         前言
0x01         CSP概念
0x02         CSP發展時間軸
0x03         CSP語法
0x04         CSP預設特性
0x05         CSP例子
0x06         CSP的錯誤使用
0x07         CSP分析報告
0x08         CSP的使用率統計
0x09         CSP Bypass
0x0a         CSP總結
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)是一種以可信白名單作機制,來限制網站中是否可以包含某來源內容。預設配置下不允許執行內聯程式碼(<script>塊內容,內聯事件,內聯樣式),以及禁止執行eval() , newFunction() , setTimeout([string], …) 和setInterval([string], …) 。

0x02 CSP發展時間軸


毋容置疑CSP是一個偉大的策略,但CSP從最初設計到被W3C認可制定成通用標準,卻經歷了一個漫長而曲折的過程。

CSP模型首次被提出

這要從2007年說起,當時XSS攻擊已經在OWASP TOP10攻擊中排名第一位,CSP的最初的設想就在這一年被Mozilla專案組的Gervase Markham和WEB安全界大牛Robert Hansen ‘rsnake’兩人共同提出的。

瀏覽器首次使用CSP

2011年3月Firefox 4.0釋出,首次把CSP當作一種正式的安全策略規範使用到瀏覽器中。當時火狐使用的是自己定義的X-Content-Security-Policy頭。單從CSP推廣上來看,Firefox4.0的釋出是劃時代的,雖然此時的CSP只是Firefox自己定義的一個內部標準。但在此之後,CSP的概念被全球迅速推廣。

Chrome使用CSP

隨後在2011年9月,谷歌在Chrome瀏覽器14.0版本釋出時加入CSP,而Chrome瀏覽器使用的也是自己的CSP標準,它使用X-Webkit-CSP頭進行對CSP的解析,這個頭從字面上更能看出來Chrome瀏覽器使用的是Webkit核心。此時世界主流的2大瀏覽器Chrome、Firefox都已經支援了CSP。

W3C起草CSP標準

作為標準釋出的W3C組織順其自然在2011年11月在官網上釋出了CSP1.0草案。W3C的CSP1.0草案的語法和Firefox和Chrome中截然不同,隨著時間的推移1年後,W3C的CSP1.0草案已經到了推選階段,基本可以正式釋出。

全面支援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檢視

NewImagecspuse

0x03 CSP語法


CSP1.0指令

NewImage

CSP1.1新增指令

NewImage

CSP語法

NewImage

0x04 CSP預設特性


阻止內聯程式碼執行

CSP除了使用白名單機制外,預設配置下阻止內聯程式碼執行是防止內容注入的最大安全保障。這裡的內聯程式碼包括:<script>塊內容,內聯事件,內聯樣式。

(1) script程式碼,<script>……<scritp>

對於<script>塊內容是完全不能執行的。例如:

#!html
<script>getyourcookie()</script>

(2) 內聯事件

#!html
<a href="" onclick="handleClick();"></a>
<a href="javascript:handleClick();"></a>

(3) 內聯樣式

#!html
<div style="display:none"></div>

雖然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.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編寫,可以協助和幫助網站管理員編寫出適合自己站點的CSP。http://cspisawesome.com/

NewImage

0x06 CSP的錯誤使用


CSP的語法和指令並不複雜,但如果沒有充分了解網站業務和安全需求,錯誤的使用CSP則會適得其反。

(1)我在2013年底訪問http://www.grosshandel-hahn.de/,發現CSP策略明顯使用錯誤。

NewImage

可以看到使用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
<!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格式。

#!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
<?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);
?>

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策略更加嚴謹。

NewImage

http://blog.veracode.com/2013/11/security-headers-on-the-top-1000000-websites-november-2013-report/

對於國內網站使用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在國內就應該廣泛的給網站管理員進行科普。

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
<?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

策略優先順序繞過

在瀏覽器的保護策略中,有很多是重複的。比如A策略可以抵禦C攻擊,B策略也可以抵禦C攻擊。此處的抵禦可以是阻斷也可以是放行。於是當AB同時作用於C攻擊上時,Bypass就可能發生。

(1)Iframe sandbox 和 CSP sandbox

當iframe sandbox允許執行JS,而CSP不允許執行JS,問題就發生了,CSP就被bypass了。

#!php
//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。

0x0a CSP總結


充分了解CSP安全策略的語法和指令,並最大程度的合理的去利用和部署這些策略,努力把安全策略發揮到極致,使其最終把危害降低到最低。

CSP並不能消除內容注入攻擊,但可以有效的檢測並緩解跨站攻擊和內容注入攻擊帶來的危害。

CSP不是做為防禦內容注入(如XSS)的第一道防線而設計,而最適合部署在縱深防禦體系中。

關於為什麼CSP的使用率如此之低。究其原因,CSP雖然提供了強大的安全保護,但是他也造成了如下問題:Eval及相關函式被禁用、內嵌的JavaScript程式碼將不會執行、只能透過白名單來載入遠端指令碼。這些問題阻礙CSP的普及,如果要使用CSP技術保護自己的網站,開發者就不得不花費大量時間分離內聯的JavaScript程式碼和做一些調整。

沒有被繞過的策略不是好的策略,而從辯證角度來講,多載入一種安全策略,就多了一種Bypass的維度。在安全領域“Bypass”始終是一個曼妙而鬼魅的名字。

應該把CSP安全策略視為是一把可以直插心臟的鋒利的尖刀,而不是一根電線杆子杵在那。

0x0b 參考


http://www.w3.org/TR/CSP11/ http://www.w3.org/TR/CSP/ http://www.html5rocks.com/en/tutorials/security/content-security-policy/ http://ruxcon.org.au/assets/slides/CSP-kuza55.pptx https://code.google.com/p/mustache-security/wiki/AngularJS http://content-security-policy.com/ https://github.com/blog/1477-content-security-policy http://cspisawesome.com/ https://developer.mozilla.org/en-US/docs/Security/CSP/Using_Content_Security_Policy http://benvinegar.github.io/csp-talk-2013/#1 http://caniuse.com/#feat=contentsecuritypolicy https://www.imququ.com/post/content-security-policy-reference.html http://docs.angularjs.org/api/ng.directive:ngCsp https://developer.mozilla.org/en-US/docs/Security/CSP/Using_CSP_violation_reports http://stackoverflow.com/questions/14629534/json-post-in-php-csp-report http://mathiasbynens.be/notes/csp-reports http://www.madirish.net/556 http://www.veracode.com/blog/2013/11/security-headers-on-the-top-1000000-websites-november-2013-report/ https://github.com/google/CSP-Validator http://www.benmarshall.me/content-security-policy/ http://www.slideshare.net/x00mario/jsmvcomfg-to-sternly-look-at-javascript-mvc-and-templating-frameworks http://trends.builtwith.com/javascript/Angular-JS http://developer.chrome.com/extensions/contentSecurityPolicy http://cs.ucsb.edu/~adoupe/static/dedacota-ccs2013.pdf

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章