<a href="http://jaq.alibaba.com/community/art/show?articleid=557">csp的今世與未來</a>
一、從兩個工具說起
下面的清單中會給出評估工具對你輸入csp的安全性評估,所有條目用不同顔色标記了可能的影響程度。并且每個條目都可以單擊展開詳情,以按照建議修複可能存在的缺陷。如圖:

為了研究csp(content security policy)對xss攻擊的防護作用,他們做了對csp安全模型的首次深入分析,分析了csp标準中對web缺陷的保護能力,幫助識别常見的csp政策配置的可能錯誤,并且展示了三類能使csp無效化的繞過方法。
這次研究所采用的材料基于從google搜尋的索引檔案中所提取到的csp政策,從語料庫中提取了大約1060億頁的頁面,其中39億是受csp保護的,其中确認了26,011個獨立的政策。他們發現,由于政策配置錯誤和白名單條目不安全,這些政策中至少有94.72%無法緩解xss攻擊。基于這樣的研究結果,他們建議在實踐中部署csp時,使用基于nonce的方法而不是傳統的白名單。并且,他們提出了名為“strict dynamic”的新特性,這是目前在chromium浏覽器中實作的csp3規範的一個新特性。以下會詳細講述為何要使用這種政策和特性。
首先,何為csp?我們知道,内容安全政策(csp)是一種聲明機制,允許web開發者在其應用程式上指定多個安全限制,由支援的使用者代理(浏覽器)來負責強制執行。csp旨在“作為開發人員可以使用的工具,以各種方式保護其應用程式,減輕内容注入漏洞的風險和減少它們的應用程式執行的特權”。目前,csp還處在快速的發展期,目前正在進行規範中的版本是csp3,csp标準由使用者代理選擇實作。例如,chromium具有完整的csp2支援,并且實作了csp3的大部分工作草案,僅在某些情況下可能會落後于實驗中的某些特性,而mozillafirefox和基于webkit的浏覽器則剛剛獲得了完整的csp2支援。在實際使用中,csp政策在content-security-policy http響應頭或<meta>元素中提供。
1、資源加載限制。csp的最廣為人知和常用的方面是将各種子資源的加載限制到開發人員允許的一組源的能力,這組源稱為源清單。 常用的指令是script-src,style-src,img-src和兜底的 default-src; 調節資源的指令的完整清單如下表1所示。作為特殊情況,script-src和style-src指令還有幾個額外的配置選項可用; 這些選項允許對腳本和樣式表進行更細粒度的控制。
2、基于url的限制。某些類型的攻擊不能通過管理子資源來防止,但與之類似,對于文檔也需要有可以與之互動的可信來源的概念。 一個常見的例子是frameancestors指令,它定義了允許的架構來源,以防止點選劫持。 類似地,base-uri和form-action定義哪些url可以是<base#href>和<form#action>元素的目标,以防止一些post xss攻擊。
3、雜項限制和強化選項。由于在web應用程式中缺乏能夠啟用安全限制的其他常見機制,csp已經成為幾個松散适用的安全功能的集合。這些功能包括block-all-mixed-content和upgrade-insecurerequests,它們可以防止https混合内容錯誤并幫助改進https支援; plugin-types能夠限制允許的插件格式; 還有sandbox,它反映了html5沙箱架構的安全功能。
xss:xss攻擊能在一個脆弱的應用程式中注入并執行不受信任的腳本(用script-src和object-src指令來進行保護)
clickjacking:clickjacking通過在攻擊者控制的頁面上覆寫隐藏的架構來迫使使用者在受影響的應用程式中執行不想要的操作。(通過限制架構嵌入和 frame-ancestors指令來保護)
mixed content:mixedcontent意味着在通過用https傳遞的頁面上使用不安全協定加載資源(使用upgrade-insecure-requests和blockall-mixed-content關鍵字進行保護,限制将腳本和敏感資源加載到https網頁中)
在談論csp帶來的好處之前,我們需要注意到。由于一些比較受歡迎的使用者代理(浏覽器)還不支援或者僅對csp提供部分支援,是以如果應用僅僅依賴csp作為深度防禦的手段會很容易讓安全機制完全失敗。是以,在使用csp之外還必須采用傳統保護機制; 例如,在生成html代碼時使用帶有嚴格上下文轉義的架構,使用x-frame-optionsheader以防止點選劫持,并確定資源在安全頁面上通過https協定擷取。請務必記住,設定csp的實際好處是,當主要的安全機制不夠用時,csp可以在開發人員引入程式設計錯誤時保護使用者遠離可能導緻的xss,點選劫持或者混合内容錯誤。
事實上,由于點選劫持可以通過x-frame-options來避免,而混合内容錯誤在現代浏覽器中已經預設被阻止了。是以csp作為标準被提出的最主要目的,就是用于防護xss攻擊。而xss,也正是既能通過csp來緩解,又是開發者經常容易引入應用的錯誤。在實作用csp防止不必要的腳本執行時,我們制定的政策必須滿足三個要求:
1、政策必須同時定義script-src和object-src(或者使用default-src來補全),在缺少任意一項時均可以被繞過:
2、script-src的源清單不能包含unsafe-inline關鍵詞(除非使用nonce)或者允許data: uri,否則可以被繞過:
3、script-src和object-src源清單不能包含含有攻擊者可控制response的安全相關部分的源位址,或包含不安全的庫。否則可以被繞過:
如果以上任意一條沒有被滿足的話,整個csp對于xss的防護就會徹底失效。
由于csp的基本假設之一就是在政策白名單中的域名隻會提供安全的内容,是以從理論上來說攻擊者不應該能夠将有效的javascript注入到白名單裡來源的響應中。然而在實踐中,我們發現現代web應用程式往往會因為幾種模式違反這個假設。
1、javascript帶有使用者可控的回調:某些jsonp函數接受使用者傳遞的函數名,但未做嚴格的過濾,導緻可以注入任意javascript代碼執行,即使做了基本的過濾,也可能使用some攻擊來注入任意函數名:
2、反射或者符号執行:csp對于腳本執行的限制可能(通常是意外地)被白名單中的腳本所規避。例如,腳本可以使用反射來查找和調用全局作用域中的函數,如圖:
通常情況下這些函數不會有太大危害,因為參數是開發人員所控制的。然而當函數從dom擷取資料,而應用又有dom注入的漏洞,則很可能被攻擊者完全控制函數及其參數。一個典型的例子是目前流行的angularjs庫,它具有強大的模闆文法和用戶端模闆執行:
預設情況下angularjs會通過eval來執行代碼,在特定的不允許eval的csp場景下,angularjs也支援使用“csp compatibility mode” (ng-csp)來執行模闆的代碼。攻擊者隻需要從白名單中的域名裡引入angularjs,就可以在頁面上通過注入ng-app标簽來編寫能夠執行任意javascript代碼的模闆。
3、意料之外的可被當做的javascript來解析的響應:通過浏覽器對mime的檢查寬松來執行任意js,比如僞造腳本響應類型。如果被黑客控制響應的話,在白名單中script-src和object-src都可能存在隐患。
4、作為安全手段的路徑限制:csp2中的whitelist可以指定路徑(目錄),然而如果白名單中的條目包含30x重定向,且能被黑客控制,則可以繞過csp。
最常見于oauth中,或被用于防止referer丢失。
為了找出網際網路中有多少csp政策能夠切實有效地防護xss攻擊,google團隊構造了一些資料集并進行了标準化處理。根據我們以上的結論,想要達到好的xss防護效果,csp的xss保護政策必須處在強制模式下,并且至少包含以下兩個指令之一:script-src或default-src。是以可以據此确定含有xss防護的csp政策。
1、對于”unsafe-inline”的使用:對于一個使用了“unsafe-inline”并且沒有使用nonce的政策,可以認為是很容易被繞過的。
2、缺少“object-src”:一個指定了“script-src”政策但是沒有指定“object-src”(同時也沒有“default-src”)的政策,是很容易用plugin繞過的。
3、在白名單中使用通配符:在白名單中使用通配符,或者使用uri scheme很容易引起包含任意域名内容。
4、白名單中包含不安全的來源:如果白名單中的來源可能存在csp bypass,則也是不安全的。
1、托管了angularjs的域名,因為angularjs允許在模闆中執行任意代碼。
2、暴露了jsonp接口的域名(可以使用jsonp任意定義js代碼,或者some攻擊自定義函數名)。
在進行了一系列資料的處理和分析之後,他們得到的結論是。在資料集中,有3,913,578,446(3.7%)個網址采用了csp。 所有主機名中的1,664,019(0.16%)采用了csp。
1、所有政策
2、xss-protection 政策(至少含有script-src,object-src或者default-src之一)
3、嚴格xss-protection政策(在2的基礎上,不含unsafe-inline,unsafe-eval等,且uri scheme,或者白名單通配符)
1、所有政策資料中的94.72%并沒有提供xss防護
2、在所有提供xss防護的資料中,有94.68%可以被繞過
3、在所有提供xss防護的資料中,有87.3%指定了unsafe-inline并且沒有部署nonce
4、在所有提供xss防護的資料中,有9.4%既沒有指定object-src,也沒有default-src
5、在所有提供xss防護的資料中,有21.48%使用了通配符或者uri scheme
6、在忽略3,5的情況下,仍有51.05%的可以被繞過。有些是因為4,更多的是因為script-src中的白名單中包含了不安全的域
1、白名單數量越大,越難保證jsonp和angularjs造成的安全問題
2、大概在嚴格政策中的41.65%,所有xss防護政策中的79.17%,包含不安全的白名單
3、在使用12條白名單時,繞過率達到了94.8%
4、作為結果,我們得出的結論是,部署傳統的基于白名單的csp模型中防止xss是不可行的,因為在實踐中腳本執行限制通常可以被推翻。
可以看出,script-src的白名單是造成csp失效的最大原因(除了沒配置好的unsafe-inline和缺少object-src之外)。是以,我們應該如何改進csp呢。其實csp已經提供了更精細的方法來對信任腳本:加密随機數(cryptographic nonce)和哈希(hash)。 特别是nonces允許開發人員明确地注解每個受信任的腳本(不論内聯和外部),同時禁止攻擊者注入的腳本執行。 為了提高csp的整體安全性,google據此提出了一種稍微不同的政策寫法。 應用程式維護者應該應用基于nonce的保護方法,而不是依賴白名單。 以下清單描述了基于白名單的csp政策和滿足此政策的腳本:
可以看出,白名單中包含了一個不安全的域名,是以所述csp的政策就是不安全的。攻擊者可以通過jsonp暴露出的點來注入惡意代碼: https://example.org/script?callback=malicious_code.
為了防止這種事情的發生,我們使用nonce來定義政策。在nonce中,應用程式定義并生成了單一的,不可猜測的令牌(nonce),這個令牌會同時傳遞給csp政策和作為一個合法html屬性傳遞給script。 使用者代理僅允許執行那些nonce值能夠比對政策中指定的值的腳本。雖然攻擊者可以将标記注入易受攻擊的頁面,但是由于不知道nonce的臨時值,是以他并不能執行惡意腳本。
通過使用nonce,可以單獨将腳本列入白名單。 即使攻擊者能夠定位xss,nonce的值也是不可預測的,是以攻擊者不可能向jsonp注入有效腳本。而且由于浏覽器支援多個政策,是以可以把nonce和whitelist一起寫,用逗号隔開。nonce可以用來将各個腳本列入白名單,而whitelist可以用于集中實施安全政策。
那麼,當我們生成動态腳本并插入時會發生什麼呢?因為新生成的,被插入到頁面的js并不知道nonce的值,是以會被攔截,是以需要csp3裡的 script-src: ’strict-dynamic’。 ’strict-dynamic’允許将信任關系傳遞給動态生成的腳本,也就是說,“strict-dynamic”允許js動态添加的腳本執行,而忽略script-src的白名單。并且,其他的script-src白名單會被忽略,浏覽器不會執行靜态或解析器插入的腳本,除非它伴随有效的nonce值。這裡的關鍵點是,使用createelement()來插入js時,能夠執行createelement()的js已經被信任了,并且黑客不知道nonce的時候無法注入惡意腳本。是以我們可以信任建立的js代碼。舉例,我們可以這麼寫csp:
使用這樣的政策時,開發者将需要向靜态<script>元素添加nonce,但是會確定隻有這些受信任的腳本及其後代才會執行腳本。這種部署csp的模式可以顯著地提高政策的安全性并促進大家使用。
當然,nonce-based 政策并不是xss的靈丹妙藥,它也有它的局限性。
1、如果xss的根本原因是将uri中的不受信任資料傳遞到script的src屬性中,并且通過createelement建立,那麼strict-dynamic政策将允許其執行,反而是傳統的whitelist會阻止它。
2、如果在noncedscript标簽中有注入點,那麼攻擊者仍然可以執行攻擊。(這點傳統csp也一樣)
3、post-xss/scriptlessattacks,仍然無法防禦。
1、對于解析器插入的腳本:如果使用document.write()來插入腳本,會被strict-dynamic政策阻止。使用者必須使用createelement()或者在document.write()建立的腳本中顯式傳遞一個nonce
2、内聯事件處理程式:strict-dynamic不會花費時間去移除和csp不相容的标記(例如javascript: 開頭的url,或者内聯的事件處理程式),開發者需要自己去重構。
3、針對google内部資料集的幾百個xss案例的分析表明絕大部分的xss攻擊都能被 nonce-based政策所減輕,并且這種政策明顯比白名單更容易被開發人員接受。
最後,總結一下google這次調研的結論。他們對csp的安全模型進行了深入分析,并确定了其中看似安全的政策沒有提供安全改進。他們在超過10億個主機名中調查了csp的采用情況,并在google搜尋索引中确定了160萬個主機在使用26,011個獨特的政策。通過自動化檢查,發現所有政策中的94.72%能被輕易繞過。所有政策中的75.81%和嚴格政策中的41.65%在白名單中也至少包括一個不安全主機。正是這些數字讓我們相信白名單是不切實際的。
是以,google提出一個新的政策方式。建議使用單個腳本的csp nonces代替整個主機列入白名單的方式。并且,為了簡化基于nonce的csp,提出了strict-dynamic關鍵字。啟用了這個關鍵字的網站在浏覽器中會繼承nonce到動态腳本中。是以,一個受nocne信任的腳本在運作中所執行的新腳本是被信任的。
雖然這種技術脫離了傳統的主機白名單方法的csp,但他們認為可用性改進足夠大到足以證明其廣泛采用。希望基于nonce的方法的組合和'strict-dynamic'關鍵字将允許開發人員群組織最終能夠享受由内容安全政策提供的真正的安全利益。
在看到google煞費苦心的這麼多幫助推廣csp部署的工具,以及認真的深度調研後,我堅信csp的今世可能還未能盡如人意,但是未來在google以及其它各家标準制定者的大力推動下,改進後的csp必能夠在現代浏覽器的xss防禦中大放異彩。
本文來自合作夥伴“阿裡聚安全”,發表于2016年10月17日 16:39.