爲了防止它們,要採起不少編程措施,很是麻煩。不少人提出,能不能根本上解決問題,瀏覽器自動禁止外部注入惡意腳本?這就是"網頁安全政策"(Content Security Policy,縮寫 CSP)的來歷。本文詳細介紹如何使用 CSP 防止 XSS 攻擊。 javascript
CSP 的實質就是白名單制度,開發者明確告訴客戶端,哪些外部資源能夠加載和執行,等同於提供白名單。它的實現和執行所有由瀏覽器完成,開發者只需提供配置。CSP 大大加強了網頁的安全性。攻擊者即便發現了漏洞,也無法注入腳本,除非還控制了一臺列入了白名單的可信主機。html
兩種方法能夠啓用 CSP。一種是經過 HTTP 頭信息的Content-Security-Policy的字段。html5
Content-Security-Policy: script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:
另外一種是經過網頁的<meta>標籤。java
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
上面代碼中,CSP 作了以下配置。編程
腳本:只信任當前域名json
標籤:不信任任何URL,即不加載任何資源 樣式表:只信任cdn.example.org和third-party.org跨域 框架(frame):必須使用HTTPS協議加載瀏覽器 其餘資源:沒有限制安全 啓用後,不符合 CSP 的外部資源就會被阻止加載。 Chrome 的報錯信息。 Firefox 的報錯信息。 2、限制選項 CSP 提供了不少限制選項,涉及安全的各個方面。 2.1 資源加載限制 如下選項限制各種資源的加載。 script-src:外部腳本 style-src:樣式表 img-src:圖像 media-src:媒體文件(音頻和視頻) font-src:字體文件 object-src:插件(好比 Flash) child-src:框架 frame-ancestors:嵌入的外部資源(好比<frame>、<iframe>、<embed>和<applet>) connect-src:HTTP 鏈接(經過 XHR、WebSockets、EventSource等) worker-src:worker腳本 manifest-src:manifest 文件 2.2 default-src default-src用來設置上面各個選項的默認值。 Content-Security-Policy: default-src 'self' 上面代碼限制全部的外部資源,都只能從當前域名加載。若是同時設置某個單項限制(好比font-src)和default-src,前者會覆蓋後者,即字體文件會採用font-src的值,其餘資源依然採用default-src的值。 2.3 URL 限制 有時,網頁會跟其餘 URL 發生聯繫,這時也能夠加以限制。 frame-ancestors:限制嵌入框架的網頁 base-uri:限制 <base#href> form-action:限制 <form#action> 2.4 其餘限制 其餘一些安全相關的功能,也放在了 CSP 裏面。 block-all-mixed-content:HTTPS 網頁不得加載 HTTP 資源(瀏覽器已經默認開啓) upgrade-insecure-requests:自動將網頁上全部加載外部資源的 HTTP 連接換成 HTTPS 協議 plugin-types:限制可使用的插件格式 sandbox:瀏覽器行爲的限制,好比不能有彈出窗口等。 2.5 report-uri 有時,咱們不只但願防止 XSS,還但願記錄此類行爲。report-uri就用來告訴瀏覽器,應該把注入行爲報告給哪一個網址。 Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser; 上面代碼指定,將注入行爲報告給/my_amazing_csp_report_parser這個 URL。 瀏覽器會使用POST方法,發送一個JSON對象,下面是一個例子。 { "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" } } 3、Content-Security-Policy-Report-Only 除了Content-Security-Policy,還有一個Content-Security-Policy-Report-Only字段,表示不執行限制選項,只是記錄違反限制的行爲。它必須與report-uri選項配合使用。 Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser; 4、選項值 每一個限制選項能夠設置如下幾種值,這些值就構成了白名單。 主機名:example.org,https://example.com:443 路徑名:example.org/resources/js/ 通配符:*.example.org,*://*.example.com:*(表示任意協議、任意子域名、任意端口) 協議名:https:、data: 關鍵字'self':當前域名,須要加引號 關鍵字'none':禁止加載任何外部資源,須要加引號 多個值也能夠並列,用空格分隔。 Content-Security-Policy: script-src 'self' https://apis.google.com 若是同一個限制選項使用屢次,只有第一次會生效。 # 錯誤的寫法 script-src https://host1.com; script-src https://host2.com # 正確的寫法 script-src https://host1.com https://host2.com 若是不設置某個限制選項,就是默認容許任何值。 5、script-src 的特殊值 除了常規值,script-src還能夠設置一些特殊值。注意,下面這些值都必須放在單引號裏面。 'unsafe-inline':容許執行頁面內嵌的<script>標籤和事件監聽函數 unsafe-eval:容許將字符串看成代碼執行,好比使用eval、setTimeout、setInterval和Function等函數。 nonce值:每次HTTP迴應給出一個受權token,頁面內嵌腳本必須有這個token,纔會執行 hash值:列出容許執行的腳本代碼的Hash值,頁面內嵌腳本的哈希值只有吻合的狀況下,才能執行。 nonce值的例子以下,服務器發送網頁的時候,告訴瀏覽器一個隨機生成的token。 Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa' 頁面內嵌腳本,必須有這個token才能執行。 <script nonce=EDNnf03nceIOfn39fn3e9h3sdfa> // some code </script> hash值的例子以下,服務器給出一個容許執行的代碼的hash值。 Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng=' 下面的代碼就會容許執行,由於hash值相符。 <script>alert('Hello, world.');</script> 注意,計算hash值的時候,<script>標籤不算在內。 除了script-src選項,nonce值和hash值還能夠用在style-src選項,控制頁面內嵌的樣式表。 6、注意點 (1)script-src和object-src是必設的,除非設置了default-src。 由於攻擊者只要能注入腳本,其餘限制均可以規避。而object-src必設是由於 Flash 裏面能夠執行外部腳本。 (2)script-src不能使用unsafe-inline關鍵字(除非伴隨一個nonce值),也不能容許設置data:URL。 下面是兩個惡意攻擊的例子。 <img src="x" onerror="evil()"> <script src="data:text/javascript,evil()"></script> (3)必須特別注意 JSONP 的回調函數。 <script src="/path/jsonp?callback=alert(document.domain)//"> </script> 上面的代碼中,雖然加載的腳原本自當前域名,可是經過改寫回調函數,攻擊者依然能夠執行惡意代碼。 7、參考連接 CSP Is Dead, Long Live CSP! , by Lukas Weichselbaum An Introduction to Content Security Policy , by Mike West 做者:阮一峯@螞蟻金服,更多安全類文章,請訪問阿里聚安全博客 posted on 2016-09-30 15:54 阿里聚安全 閱讀(...) 評論(...) 編輯 收藏 刷新評論 刷新頁面 返回頂部 導航 博客園 首頁 聯繫 訂閱 管理 統計 隨筆 - 158 文章 - 1 評論 - 224 api
樣式表:只信任cdn.example.org和third-party.org跨域
框架(frame):必須使用HTTPS協議加載瀏覽器
其餘資源:沒有限制安全
啓用後,不符合 CSP 的外部資源就會被阻止加載。
Chrome 的報錯信息。
Firefox 的報錯信息。
CSP 提供了不少限制選項,涉及安全的各個方面。
如下選項限制各種資源的加載。
script-src:外部腳本
style-src:樣式表
img-src:圖像
media-src:媒體文件(音頻和視頻)
font-src:字體文件
object-src:插件(好比 Flash)
child-src:框架
frame-ancestors:嵌入的外部資源(好比<frame>、<iframe>、<embed>和<applet>)
connect-src:HTTP 鏈接(經過 XHR、WebSockets、EventSource等)
worker-src:worker腳本
manifest-src:manifest 文件
default-src用來設置上面各個選項的默認值。
Content-Security-Policy: default-src 'self'
上面代碼限制全部的外部資源,都只能從當前域名加載。若是同時設置某個單項限制(好比font-src)和default-src,前者會覆蓋後者,即字體文件會採用font-src的值,其餘資源依然採用default-src的值。
有時,網頁會跟其餘 URL 發生聯繫,這時也能夠加以限制。
frame-ancestors:限制嵌入框架的網頁
base-uri:限制 <base#href>
form-action:限制 <form#action>
其餘一些安全相關的功能,也放在了 CSP 裏面。
block-all-mixed-content:HTTPS 網頁不得加載 HTTP 資源(瀏覽器已經默認開啓)
upgrade-insecure-requests:自動將網頁上全部加載外部資源的 HTTP 連接換成 HTTPS 協議
plugin-types:限制可使用的插件格式
sandbox:瀏覽器行爲的限制,好比不能有彈出窗口等。
有時,咱們不只但願防止 XSS,還但願記錄此類行爲。report-uri就用來告訴瀏覽器,應該把注入行爲報告給哪一個網址。
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
上面代碼指定,將注入行爲報告給/my_amazing_csp_report_parser這個 URL。 瀏覽器會使用POST方法,發送一個JSON對象,下面是一個例子。
{ "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" } }
除了Content-Security-Policy,還有一個Content-Security-Policy-Report-Only字段,表示不執行限制選項,只是記錄違反限制的行爲。它必須與report-uri選項配合使用。
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
每一個限制選項能夠設置如下幾種值,這些值就構成了白名單。
主機名:example.org,https://example.com:443
路徑名:example.org/resources/js/
通配符:*.example.org,*://*.example.com:*(表示任意協議、任意子域名、任意端口)
協議名:https:、data:
關鍵字'self':當前域名,須要加引號
關鍵字'none':禁止加載任何外部資源,須要加引號
多個值也能夠並列,用空格分隔。
Content-Security-Policy: script-src 'self' https://apis.google.com
若是同一個限制選項使用屢次,只有第一次會生效。
# 錯誤的寫法 script-src https://host1.com; script-src https://host2.com # 正確的寫法 script-src https://host1.com https://host2.com
若是不設置某個限制選項,就是默認容許任何值。
除了常規值,script-src還能夠設置一些特殊值。注意,下面這些值都必須放在單引號裏面。
'unsafe-inline':容許執行頁面內嵌的<script>標籤和事件監聽函數
unsafe-eval:容許將字符串看成代碼執行,好比使用eval、setTimeout、setInterval和Function等函數。
nonce值:每次HTTP迴應給出一個受權token,頁面內嵌腳本必須有這個token,纔會執行
hash值:列出容許執行的腳本代碼的Hash值,頁面內嵌腳本的哈希值只有吻合的狀況下,才能執行。
nonce值的例子以下,服務器發送網頁的時候,告訴瀏覽器一個隨機生成的token。
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
頁面內嵌腳本,必須有這個token才能執行。
<script nonce=EDNnf03nceIOfn39fn3e9h3sdfa> // some code </script>
hash值的例子以下,服務器給出一個容許執行的代碼的hash值。
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
下面的代碼就會容許執行,由於hash值相符。
<script>alert('Hello, world.');</script>
注意,計算hash值的時候,<script>標籤不算在內。
除了script-src選項,nonce值和hash值還能夠用在style-src選項,控制頁面內嵌的樣式表。
(1)script-src和object-src是必設的,除非設置了default-src。
由於攻擊者只要能注入腳本,其餘限制均可以規避。而object-src必設是由於 Flash 裏面能夠執行外部腳本。
(2)script-src不能使用unsafe-inline關鍵字(除非伴隨一個nonce值),也不能容許設置data:URL。
下面是兩個惡意攻擊的例子。
<img src="x" onerror="evil()"> <script src="data:text/javascript,evil()"></script>
(3)必須特別注意 JSONP 的回調函數。
<script src="/path/jsonp?callback=alert(document.domain)//"> </script>
上面的代碼中,雖然加載的腳原本自當前域名,可是經過改寫回調函數,攻擊者依然能夠執行惡意代碼。
CSP Is Dead, Long Live CSP! , by Lukas Weichselbaum
An Introduction to Content Security Policy , by Mike West
posted on 2016-09-30 15:54 阿里聚安全 閱讀(...) 評論(...) 編輯 收藏