HTTP 的內容安全策略(CSP)

Jerry Qu發表於2015-07-19

本文介紹的是W3C的Content Security Policy,簡稱CSP。顧名思義,這個規範與內容安全有關,主要是用來定義頁面可以載入哪些資源,減少XSS的發生。

HTTP 的內容安全策略(CSP)

Chrome擴充套件已經引入了CSP,通過manifest.json中的content_security_policy欄位來定義。一些現代瀏覽器也支援通過響應頭來定義CSP。下面我們主要介紹如何通過響應頭來使用CSP,Chrome擴充套件中CSP的使用可以參考Chrome官方文件

瀏覽器相容性

早期的Chrome是通過X-WebKit-CSP響應頭來支援CSP的,而firefox和IE則支援X-Content-Security-Policy,Chrome25和Firefox23開始支援標準的的Content-Security-Policy,見下表。

響應頭 Chrome Firefox Safari IE
Content-Security-Policy 25+ 23+ - -
X-Content-Security-Policy - 4.0+ - 10.0(有限的)
X-Webkit-CSP 14+ - 6+ -

完整的瀏覽器CSP支援情況請移步CanIUse

如何使用

要使用CSP,只需要服務端輸出類似這樣的響應頭就行了:

Content-Security-Policy: default-src 'self'

default-src是CSP指令,多個指令之間用英文分號分割;’self’是指令值,多個指令值用英文空格分割。目前,有這些CSP指令:

指令 指令值示例 說明
default-src ‘self’ cnd.a.com 定義針對所有型別(js、image、css、web font,ajax請求,iframe,多媒體等)資源的預設載入策略,某型別資源如果沒有單獨定義策略,就使用預設的。
script-src ‘self’ js.a.com 定義針對JavaScript的載入策略。
style-src ‘self’ css.a.com 定義針對樣式的載入策略。
img-src ‘self’ img.a.com 定義針對圖片的載入策略。
connect-src ‘self’ 針對Ajax、WebSocket等請求的載入策略。不允許的情況下,瀏覽器會模擬一個狀態為400的響應。
font-src font.a.com 針對Web Font的載入策略。
object-src ‘self’ 針對<object>、<embed>或<applet>等標籤引入的flash等外掛的載入策略。
media-src media.a.com 針對<audio>或<video>等標籤引入的html多媒體的載入策略。
frame-src ‘self’ 針對frame的載入策略。
sandbox allow-forms 對請求的資源啟用sandbox(類似於iframe的sandbox屬性)。
report-uri /report-uri 告訴瀏覽器如果請求的資源不被策略允許時,往哪個地址提交日誌資訊。 特別的:如果想讓瀏覽器只彙報日誌,不阻止任何內容,可以改用Content-Security-Policy-Report-Only頭。

指令值可以由下面這些內容組成:

指令值 指令示例 說明
img-src 允許任何內容。
‘none’ img-src ‘none’ 不允許任何內容。
‘self’ img-src ‘self’ 允許來自相同來源的內容(相同的協議、域名和埠)。
data img-src data 允許data:協議(如base64編碼的圖片)。
www.a.com img-src img.a.com 允許載入指定域名的資源。
*.a.com img-src *.a.com 允許載入a.com任何子域的資源。
https://img.com img-src https://img.com 允許載入img.com的https資源(協議需匹配)。
https: img-src https: 允許載入https資源。
‘unsafe-inline’ script-src ‘unsafe-inline’ 允許載入inline資源(例如常見的style屬性,onclick,inline js和inline css等等)。
‘unsafe-eval’ script-src ‘unsafe-eval’ 允許載入動態js程式碼,例如eval()。

從上面的介紹可以看到,CSP協議可以控制的內容非常多。而且如果不特別指定’unsafe-inline’時,頁面上所有inline的樣式和指令碼都不會執行;不特別指定’unsafe-eval’,頁面上不允許使用new Function,setTimeout,eval等方式執行動態程式碼。在限制了頁面資源來源之後,被XSS的風險確實小不少。

當然,僅僅依靠CSP來防範XSS是遠遠不夠的,不支援全部瀏覽器是它的硬傷。不過,鑑於低廉的開發成本,加上也沒什麼壞處。如果擔心影響面太大,也可以像下面這樣,僅收集不匹配規則的日誌,先觀察下:

Content-Security-Policy-Report-Only: script-src 'self'; report-uri http://test/

這樣,如果頁面上有inline的JS,依然會執行,只是瀏覽器會向指定地址傳送一個post請求,包含這樣的資訊:

{"csp-report":{"document-uri":"http://test/test.php","referrer":"","violated-directive":"script-src 'self'","original-policy":"script-src 'self'; report-uri http://test/","blocked-uri":""}}

相關文章