跨域腳本攻擊 XSS 是最常見、危害最大的網頁安全漏洞。為了防止它們,要采取很多編程措施,非常麻煩。很多人提出,能不能根本上解決問題,瀏覽器自動禁止外部注入惡意腳本?這就是"網頁安全政策"(Content Security Policy,縮寫 CSP)的來歷。內容安全策略(CSP),其核心思想十分簡單:網站通過發送一個 CSP 頭部,來告訴瀏覽器什么是被授權執行的與什么是需要被禁止的。其被譽為專門為解決XSS攻擊而生的神器。
1、簡述
在瀏覽網頁的過程中,尤其是移動端的網頁,經常看到有很多無關的廣告,其實大部分廣告都是所在的網絡劫持了網站響應的內容,並在其中植入了廣告代碼。為了防止這種情況發生,我們可以使用CSP來快速的阻止這種廣告植入。而且可以比較好的防御dom xss。
CSP(Content Security Policy)指的是內容安全策略 ,是一個附加的安全層,用於幫助檢測和緩解某些類型的攻擊,包括跨站腳本攻擊 (XSS) 和數據注入等攻擊。這些攻擊可用於實現從數據竊取到網站破壞或作為惡意軟件分發版本等用途。為了緩解很大一部分潛在的跨站腳本問題,瀏覽器的擴展程序系統引入了內容安全策略(CSP)的一般概念。這將引入一些相當嚴格的策略,會使擴展程序在默認情況下更加安全,開發者可以創建並強制應用一些規則,管理網站允許加載的內容。簡單來說,就是我們能夠規定,我們的網站只接受我們指定的請求資源。
內容安全策略在現代瀏覽器中已經包含,使用的是 W3C CSP 1.0 標准中描述的 Content-Security-Policy 頭部和指令。
CSP的意義:防XSS等攻擊的利器。CSP 的實質就是白名單制度,開發者明確告訴客戶端,哪些外部資源可以加載和執行,等同於提供白名單。它的實現和執行全部由瀏覽器完成,開發者只需提供配置。CSP 大大增強了網頁的安全性。攻擊者即使發現了漏洞,也沒法注入腳本,除非還控制了一台列入了白名單的可信主機。
CSP 可以由兩種方式指定:HTTP Header 和 HTML。HTTP 是在 HTTP 由增加 Header 來指定,而 HTML 級別則由 Meta 標簽指定。
CSP 有兩類:Content-Security-Policy 和 Content-Security-Policy-Report-Only。(大小寫無關)
(1)Content-Security-Policy:配置好並啟用后,不符合 CSP 的外部資源就會被阻止加載。
(2)Content-Security-Policy-Report-Only:表示不執行限制選項,只是記錄違反限制的行為。它必須與report-uri選項配合使用。
HTTP header : "Content-Security-Policy:" 策略 "Content-Security-Policy-Report-Only:" 策略
HTTP Content-Security-Policy 頭可以指定一個或多個資源是安全的,而Content-Security-Policy-Report-Only則是允許服務器檢查(非強制)一個策略。多個頭的策略定義由優先采用最先定義的。
HTML Meta : <meta http-equiv="content-security-policy" content="策略">
<meta http-equiv="content-security-policy-report-only" content="策略">
Meta 標簽與 HTTP 頭只是行式不同而作用是一致的。與 HTTP 頭一樣,優先采用最先定義的策略。如果 HTTP 頭與 Meta 定義同時存在,則優先采用 HTTP 中的定義。如果用戶瀏覽器已經為當前文檔執行了一個 CSP 的策略,則會跳過 Meta 的定義。如果 META 標簽缺少 content 屬性也同樣會跳過。
針對開發者草案中特別的提示一點:為了使用策略生效,應該將 Meta 元素頭放在開始位置,以防止提高人為的 CSP 策略注入。
CSP使用方式有兩種
1、使用meta標簽, 直接在頁面添加meta標簽
<meta http-equiv="Content-Security-Policy" content="default-src 'self' *.xx.com *.xx.cn 'unsafe-inline' 'unsafe-eval';">
這種方式最簡單,但是也有些缺陷,每個頁面都需要添加,而且不能對限制的域名進行上報。
2、在服務端配置csp
(1)Apache :
Add the following to your httpd.conf in your VirtualHost or in an .htaccess file:
Header set Content-Security-Policy "default-src 'self';"
(2)Nginx :
In your server {} block add:
add_header Content-Security-Policy "default-src 'self';";
在服務端配置所有的頁面都可以不需要改了,而且還支持上報。
如果meta、響應頭里都指定了Content-Security-Policy,則會優先使用響應頭里的Content-Security-Policy
CSP內容匹配的規則:規則名稱 規則 規則;規則名稱 規則 ...
比如:
default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';
default-src 'self' *.xx.com *.xx.cn aa.com 'unsafe-inline' 'unsafe-eval'
(*.xx.com 支持多級域名, 可以不填寫http協議)
規則解釋:
default-src 所有資源的默認策略
script-src JS的加載策略,會覆蓋default-src中的策略,比如寫了default-src xx.com;script-src x.com xx.com; 必須同時加上xx.com,因為script-src會當作一個整體覆蓋整個默認的default-src規則。
'unsafe-inline' 允許執行內聯的JS代碼,默認為不允許,如果有內聯的代碼必須加上這條
'unsafe-eval' 允許執行eval等
對自定義的協議 比如 jsxxx://aaa.com 可以寫成 jsxxx:
https協議下自動把http請求轉為https可以使用 upgrade-insecure-requests
詳情配置及瀏覽器兼容性可查看官方文檔:https://content-security-policy.com
策略應該怎么寫?示例
// 限制所有的外部資源,都只能從當前域名加載
Content-Security-Policy: default-src 'self'
// default-src 是 CSP 指令,多個指令之間用英文分號分割;多個指令值用英文空格分割
Content-Security-Policy: default-src https://host1.com https://host2.com; frame-src 'none'; object-src 'none' // 錯誤寫法,第二個指令將會被忽略
Content-Security-Policy: script-src https://host1.com; script-src https://host2.com
// 正確寫法如下
Content-Security-Policy: script-src https://host1.com https://host2.com
有時,我們不僅希望防止 XSS,還希望記錄此類行為。report-uri就用來告訴瀏覽器,應該把注入行為報告給哪個網址。
// 通過report-uri指令指示瀏覽器發送JSON格式的攔截報告到某個url地址
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser; // 報告看起來會像下面這樣
{ "csp-report": { "document-uri": "http://example.org/page.html", "referrer": "http://evil.example.com/", "blocked-uri": "http://evil.example.com/evil.js", "violated-directive": "script-src 'self' https://apis.google.com", "original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser" } }

default-src ‘self’ cdn.guangzhul.com 默認加載策略
script-src ‘self’ js.guangzhul.com 對 JavaScript 的加載策略。
style-src ‘self’ css.guangzhul.com 對樣式的加載策略。
img-src ‘self’ img.guangzhul.com 對圖片的加載策略。
connect-src ‘self’ 對 Ajax、WebSocket 等請求的加載策略。不允許的情況下,瀏覽器會模擬一個狀態為 400 的響應。
font-src font.cdn.guangzhul.com 針對 WebFont 的加載策略。
object-src ‘self’ 針對 、 或 等標簽引入的 flash 等插件的加載策略。
media-src media.cdn.guangzhul.com 針對媒體引入的 HTML 多媒體的加載策略。
frame-src ‘self’ 針對 frame 的加載策略。
report-uri /report-uri 告訴瀏覽器如果請求的資源不被策略允許時,往哪個地址提交日志信息。 特別的:如果想讓瀏覽器只匯報日志,不阻止任何內容,可以改用 Content-Security-Policy-Report-Only 頭。
指令 指令和指令值示例 指令說明
sandbox 設置沙盒環境
child-src 主要防御 <frame>,<iframe>
form-action 主要防御 <form>
frame-ancestors 主要防御 <frame>,<iframe>,<object>,<embed>,<applet>
plugin-types 主要防御 <object>,<embed>,<applet>
指令值 指令和指令值示例 指令值說明
* img-src * 允許任何內容。
‘none’ img-src ‘none’ 不允許任何內容。
‘self’ img-src ‘self’ 允許來自相同來源的內容(相同的協議、域名和端口)。
data: img-src data: 允許 data: 協議(如 base64 編碼的圖片)。
www.guangzhul.com img-src img.guangzhul.com 允許加載指定域名的資源。
*.guangzhul.com img-src *.guangzhul.com 允許加載 guangzhul.com 任何子域的資源。
‘unsafe-inline’ script-src ‘unsafe-inline’ 允許加載 inline 資源(例如常見的 style 屬性,onclick,inline js 和 inline css 等等)。
‘unsafe-eval’ script-src ‘unsafe-eval’ 允許加載動態 js 代碼,例如 eval()。