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