Web 安全之內容安全策略(Content-Security-Policy,CSP)詳解
1.CSP 簡介
內容安全策略(Content Security Policy,簡稱CSP)是一種以可信白名單作機制,來限制網站是否可以包含某些來源內容,緩解廣泛的內容注入漏洞,比如 XSS。 簡單來說,就是我們能夠規定,我們的網站只接受我們指定的請求資源。默認配置下不允許執行內聯代碼(<script>
塊內容,內聯事件,內聯樣式),以及禁止執行eval() , newFunction() , setTimeout([string], …) 和setInterval([string], …) 。
2.CSP 使用方式
CSP可以由兩種方式指定: HTTP Header 和 HTML。
-
通過定義在HTTP header 中使用:
"Content-Security-Policy:" 策略集
-
通過定義在 HTML meta標簽中使用:
<meta http-equiv="content-security-policy" content="策略集">
策略是指定義 CSP 的語法內容。
如果 HTTP 頭 與 meta 標簽同時定義了 CSP,則會優先采用 HTTP 頭的 。
定義后,凡是不符合 CSP策略的外部資源都會被阻止加載。
3.CSP 語法
3.1 策略
每一條策略都是指令與指令值組成:
Content-Security-Policy:指令1 指令值1
策略與策略之間用分號隔開,例如:
Content-Security-Policy:指令1 指令值1;指令2 指令值2;指令3 指令值3
在一條策略中,如果一個指令中有多個指令值,則指令值之間用空號隔開:
Content-Security-Policy:指令a 指令值a1 指令值a2
3.2 CSP 指令
- default-src : 定義針對所有類型(js/image/css/font/ajax/iframe/多媒體等)資源的默認加載策略,如果某類型資源沒有單獨定義策略,就使用默認的。
- script-src : 定義針對 JavaScript 的加載策略。
- style-src : 定義針對樣式的加載策略。
- img-src : 定義針對圖片的加載策略。
- font-src : 定義針對字體的加載策略。
- media-src : 定義針對多媒體的加載策略,例如:音頻標簽
<audio>
和視頻標簽<video>
。 - object-src : 定義針對插件的加載策略,例如:
<object>
、<embed>
、<applet>
。 - child-src :定義針對框架的加載策略,例如:
<frame>
,<iframe>
。 - connect-src : 定義針對 Ajax/WebSocket 等請求的加載策略。不允許的情況下,瀏覽器會模擬一個狀態為400的響應。
- sandbox : 定義針對 sandbox 的限制,相當於
<iframe>
的sandbox屬性。 - report-uri : 告訴瀏覽器如果請求的資源不被策略允許時,往哪個地址提交日志信息。
- form-action : 定義針對提交的 form 到特定來源的加載策略。
- referrer : 定義針對 referrer 的加載策略。
- reflected-xss : 定義針對 XSS 過濾器使用策略。
3.3 CSP 指令值
指令值 | 說明 |
---|---|
* | 允許加載任何內容 |
'none' | 不允許加載任何內容 |
'self' | 允許加載相同源的內容 |
www.a.com | 允許加載指定域名的資源 |
*.a.com | 允許加載 a.com 任何子域名的資源 |
https://a.com | 允許加載 a.com 的 https 資源 |
https: | 允許加載 https 資源 |
data: | 允許加載 data: 協議,例如:base64編碼的圖片 |
'unsafe-inline' | 允許加載 inline 資源,例如style屬性、onclick、inline js、inline css等 |
'unsafe-eval' | 允許加載動態 js 代碼,例如 eval() |
4.CSP 例子
-
例子1
所有內容均來自網站的自己的域:
Content-Security-Policy:default-src 'self'
-
例子2
所有內容都來自網站自己的域,還有其他子域(假如網站的地址是:a.com):
Content-Security-Policy:default-src 'self' *.a.com
-
例子3
網站接受任意域的圖像,指定域(a.com)的音頻、視頻和多個指定域(a.com、b.com)的腳本
Content-Security-Policy:default-src 'self';img-src *;media-src a.com;script-src a.com b.com
-
在線 CSP編寫的網址:http://cspisawesome.com/
5.CSP 默認特性
-
阻止內聯代碼執行
CSP除了使用白名單機制外,默認配置下阻止內聯代碼執行是防止內容注入的最大安全保障。
這里的內聯代碼包括:<script>
塊內容,內聯事件,內聯樣式。(1) script代碼,
<script>……<scritp>
對於
<script>
塊內容是完全不能執行的。例如:<script>getyourcookie()</script>
(2) 內聯事件。
<a href="" onclick="handleClick();"></a> <a href="javascript:handleClick();"></a>
(3) 內聯樣式
<div style="display:none"></div>
雖然CSP中已經對script-src和style-src提供了使用”unsafe-inline”指令來開啟執行內聯代碼,但為了安全起見還是慎用”unsafe-inline”。
-
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”這個指令。
6.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中的代碼類似與這樣:
<!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); ?>
7.參考鏈接
- http://www.ruanyifeng.com/blog/2016/09/csp.html
- http://blog.topsec.com.cn/ad_lab/content-security-policy/
- https://blog.csdn.net/qq_37943295/article/details/79978761
- https://www.jianshu.com/p/b223c5b9d5ab
- https://content-security-policy.com/
- https://www.imuo.com/a/f7566a17dcfe788216bbc5245e91a631fcc259bfac97dc7f94bf8002ba38fa21
- https://w3c.github.io/webappsec-csp/#intro
- https://kuaibao.qq.com/s/20180522G095D900?refer=spider