為什么你的網(wǎng)頁需要CSP?
內(nèi)容安全策略(CSP)是一個 HTTP Header,CSP 通過告訴瀏覽器一系列規(guī)則,嚴(yán)格規(guī)定頁面中哪些資源允許有哪些來源, 不在指定范圍內(nèi)的統(tǒng)統(tǒng)拒絕。
使用它是防止跨站點腳本(XSS)漏洞的最佳方法。由于難以使用 CSP 對現(xiàn)有網(wǎng)站進(jìn)行改造(可通過漸進(jìn)式的方法),因此 CSP 對于所有新網(wǎng)站都是強制性的,強烈建議對所有現(xiàn)有高風(fēng)險站點進(jìn)行 CSP 策略配置。
為什么要配置
CSP 的主要好處就是可以全面禁止使用不安全的嵌入式 JavaScript。內(nèi)聯(lián) JavaScript(無論是反射的還是存儲的),意味著不正確的轉(zhuǎn)義用戶輸入都可以被 Web 瀏覽器解釋為 JavaScript 代碼。通過使用 CSP 禁用嵌入式 JavaScript,你可以有效消除針對你站點的幾乎所有 XSS 攻擊。
注意,禁用內(nèi)聯(lián) JavaScript 意味著必須從 src 標(biāo)記加載所有 JavaScript <script>。直接在標(biāo)記上使用的事件處理程序(例如 onclick )將無法正常工作,<script>標(biāo)記內(nèi)的 JavaScript 也會通過。此外,使用 <style> 標(biāo)簽或 style 屬性的內(nèi)聯(lián)樣式表也將無法加載。因此為了讓 CSP 易于實現(xiàn),在設(shè)計站點時必須非常小心。
如何配置?
開啟 CSP 很簡單, 你只需要配置你的網(wǎng)絡(luò)服務(wù)器返回 Content-Security-Policy 這個 HTTP Header (有時你會看到一些關(guān)于X-Content-Security-Policy Header 的提法, 那是舊版本,你無須再如此指定它)。
除此之外,<meta> 元素也可以被用來配置該策略, 例如
- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
 
指令
無論是 header ,還是在 <meta> 標(biāo)簽中指定,其值的格式都是統(tǒng)一的,由一系列 CSP 指令(directive)組合而成。
- Content-Security-Policy: <policy-directive>; <policy-directive>
 
這里 directive,即指令,是 CSP 規(guī)范中規(guī)定用以詳細(xì)詳述某種資源的來源,比如前面示例中使用的 script-src,指定腳本可以有哪些合法來源,img-src 則指定圖片的合法淶源,以下是常用指令:
- base-uri 限制可出現(xiàn)在頁面 <base> 標(biāo)簽中的鏈接。
 - child-src 列出可用于 worker 及以 frame 形式嵌入的鏈接。譬如: child-src https://youtube.com 表示只能從 Youtube 嵌入視頻資源。
 - connect-src 可發(fā)起連接的地址 (通過 XHR, WebSockets 或 EventSource)。
 - font-src 字體來源。譬如,要使用 Google web fonts 則需要添加 font-src https://themes.googleusercontent.com 規(guī)則。
 - form-action <form>標(biāo)簽可提交的地址。
 - frame-ancestors 當(dāng)前頁面可被哪些來源所嵌入(與 child-src 正好相反)。作用于 <frame>, <iframe>, <embed>及 <applet>。該指令不能通過 <meta>指定且只對非 HTML文檔類型的資源生效。
 - frame-src 該指令已在 level 2 中廢棄但會在 level 3 中恢復(fù)使用。未指定的情況下回退到 tochild-src 指令。
 - img-src 指定圖片來源。
 - media-src 限制音視頻資源的來源。
 - object-src Flash 及其他插件的來源。
 - plugin-types 限制頁面中可加載的插件類型。
 - report-uri 指定一個可接收 CSP 報告的地址,瀏覽器會在相應(yīng)指令不通過時發(fā)送報告。不能通過 <meta> 標(biāo)簽來指定。
 - style-src 限制樣式文件的來源。
 - upgrade-insecure-requests 指導(dǎo)客戶端將頁面地址重寫,HTTP 轉(zhuǎn) HTTPS。用于站點中有大量舊地址需要重定向的情形。
 - worker-src CSP Level 3 中的指令,規(guī)定可用于 worker, shared worker, 或 service worker 中的地址。
 
預(yù)設(shè)值
除了配置指定的淶源以外,這些指令還可以配置一些預(yù)定義的值來完成一些默認(rèn)配置:
- none 不匹配任何東西。
 - self 匹配當(dāng)前域,但不包括子域。比如 example.com 可以,api.example.com 則會匹配失敗。
 - unsafe-inline 允許內(nèi)嵌的腳本及樣式。是的,沒看錯,對于頁面中內(nèi)嵌的內(nèi)容也是有相應(yīng)限制規(guī)則的。
 - unsafe-eval 允許通過字符串動態(tài)創(chuàng)建的腳本執(zhí)行,比如 eval,setTimeout 等。
 
如果頁面中非得用內(nèi)聯(lián)的寫法,還有種方式。即頁面中這些內(nèi)聯(lián)的腳本或樣式標(biāo)簽,賦值一個加密串,這個加密串由服務(wù)器生成,同時這個加密串被添加到頁面的響應(yīng)頭里面。
- <script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
 - // 這里放置內(nèi)聯(lián)在 HTML 中的代碼
 - </script>
 
頁面 HTTP 響應(yīng)頭的 Content-Security-Policy配置中包含相同的加密串:
- Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
 
配置示例
示例 1
所有內(nèi)容均來自站點的同一個源 (不包括其子域名)
Content-Security-Policy: default-src 'self'
示例 2
允許內(nèi)容來自信任的域名及其子域名 (域名不必須與CSP設(shè)置所在的域名相同)
Content-Security-Policy: default-src 'self' *.trusted.com
示例 3
允許網(wǎng)頁應(yīng)用的用戶在他們自己的內(nèi)容中包含來自任何源的圖片, 但是限制音頻或視頻需從信任的資源提供者(獲得),所有腳本必須從特定主機服務(wù)器獲取可信的代碼.
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
在這里,各種內(nèi)容默認(rèn)僅允許從文檔所在的源獲取, 但存在如下例外:
- 圖片可以從任何地方加載(注意 "*" 通配符)。
 - 多媒體文件僅允許從 media1.com 和 media2.com 加載(不允許從這些站點的子域名)。
 - 可運行腳本僅允許來自于userscripts.example.com。
 
示例 4
一個線上銀行網(wǎng)站的管理者想要確保網(wǎng)站的所有內(nèi)容都要通過SSL方式獲取,以避免攻擊者竊聽用戶發(fā)出的請求。
Content-Security-Policy: default-src https://onlinebanking.jumbobank.com
該服務(wù)器僅允許通過HTTPS方式并僅從onlinebanking.jumbobank.com域名來訪問文檔。
示例 5
一個在線郵箱的管理者想要允許在郵件里包含HTML,同樣圖片允許從任何地方加載,但不允許JavaScript或者其他潛在的危險內(nèi)容(從任意位置加載)。
Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *
注意這個示例并未指定script-src。在此CSP示例中,站點通過 default-src 指令的對其進(jìn)行配置,這也同樣意味著腳本文件僅允許從原始服務(wù)器獲取。
上報你的數(shù)據(jù)
當(dāng)檢測到非法資源時,除了控制臺看到的報錯信息,也可以讓瀏覽器將日志發(fā)送到服務(wù)器以供后續(xù)分析使用。接收報告的地址可在 Content-Security-Policy 響應(yīng)頭中通過 report-uri指令來配置。當(dāng)然,服務(wù)端需要編寫相應(yīng)的服務(wù)來接收該數(shù)據(jù)。
配置 report-uri
- Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;`
 
服務(wù)端收到請求:
- {
 - "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"
 - }
 - }
 
Report Only
CSP 提供了一種報告模式,該模式下資源不會真的被限制加載,只會對檢測到的問題進(jìn)行上報 ,以 JSON 數(shù)據(jù)的形式發(fā)送到 report-uri 指定的地方。
通過指定 Content-Security-Policy-Report-Only 而不是 Content-Security-Policy,則開啟了報告模式。
- Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
 
當(dāng)然,你也可以同時指定兩種響應(yīng)頭,各自里的規(guī)則還會正常執(zhí)行,不會互相影響。比如:
- Content-Security-Policy: img-src *;
 - Content-Security-Policy-Report-Only: img-src ‘none’; report-uri http://reportcollector.example.com/collector.cgi
 
這里圖片還是會正常加載,但是 img-src ‘none’ 也會檢測到并且發(fā)送報告。
報告模式對于測試非常有用。在開啟 CSP 之前肯定需要對整站做全面的測試,將發(fā)現(xiàn)的問題及時修復(fù)后再真正開啟,比如上面提到的對內(nèi)聯(lián)代碼的改造。
如何檢驗配置成功了?
在Network中可以看到配置成功的header:
下面是 Twitter 的一個配置示例,非常完善:
在控制臺可以看到資源 block 報錯:
Network中可以看到Block資源上報:




















 
 
 






 
 
 
 