網路的安全模型是源自於
同源政策。編程
的 https://mybank.com
只能存取 https://mybank.com
的
資料和「https://evil.example.com
」當然是一律禁止存取的。
每個來源都會與網路的其他部分隔開,確保開發人員安全無虞
並在其中建構及暢玩的沙箱。理論上來說,這超棒的於
因此,攻擊者找到了聰明的方法,能夠破壞系統。
跨網站指令碼攻擊 (XSS) 例如藉由誘騙網站 傳送惡意程式碼與預期的內容這對 Android Vitals 而言相當驚人 因為瀏覽器會將網頁上顯示的所有程式碼 屬於該網頁的安全性來源。 XSS 一覽表 是攻擊者可能使用方法的舊資料交叉段 違反這項信任。如果攻擊者成功 插入任何程式碼,往往很難達成,那就是使用者工作階段資料 而且應該保密的資訊會洩露給 The Bad Road 各位,我們顯然希望能避免這種情況。
本總覽說明瞭可以大幅降低風險並降低風險的防禦機制 XSS 攻擊對現代瀏覽器的影響:內容安全政策 (CSP)。
TL;DR
- 使用許可清單告訴用戶端允許及禁止販售的項目。
- 瞭解可用的指令。
- 瞭解它們採用的關鍵字。
- 內嵌程式碼和
eval()
都視為有害。 - 請先向伺服器回報違反政策的情形,然後再強制執行。
來源許可清單
XSS 攻擊所利用的問題在於瀏覽器無法區分
納入應用程式的指令碼和指令碼中的指令碼
遭第三方惡意植入。舉例來說,搜尋位於
從此頁面底部載入並執行
https://apis.google.com/js/plusone.js
。三
,但我們認為瀏覽器無法自行判斷該程式碼是否
apis.google.com
提供的程式碼很棒,apis.evil.example.com
但事實上可能不是瀏覽器開心地下載並執行網頁中的任何程式碼
要求 (無論來源為何)。
CSP 不會盲目信任伺服器提供的「所有項目」,而是會定義
Content-Security-Policy
HTTP 標頭,可讓您建立
,並指示瀏覽器只執行或顯示
從這些來源存取資源即使攻擊者能夠透過
插入指令碼時,該指令碼不會與許可清單相符,因此不會
執行狀態
我們相信 apis.google.com
能傳遞有效的程式碼,而且我們相信自己
接著我們再定義一項政策,僅允許指令碼在指令碼執行時執行
來自這兩個來源之一:
Content-Security-Policy: script-src 'self' https://apis.google.com
很簡單吧?您或許已經猜到,script-src
這個指令會
控制特定網頁的一組指令碼相關權限。我們已指定
將 'self'
做為有效的指令碼來源,https://apis.google.com
則當做
另一個例子。瀏覽器會從
apis.google.com
和目前網頁來源的通訊協定。
![控制台錯誤:拒絕載入指令碼「http://evil.example.com/evil.js」因為此內容違反下列《內容安全政策》指令:script-src 'self'https://apis.google.com](https://developer.chrome.google.cn/static/docs/privacy-security/csp/image/console-error-refused-l-524026adbb83a.png?authuser=19&hl=zh-tw)
定義這項政策後,瀏覽器只會擲回錯誤,而非 從其他來源載入指令碼。當聰明的攻擊者 將程式碼插入網站後,這類錯誤會長時間顯示在錯誤訊息中 而非他們預期的結果
這類政策適用於多項資源
雖然指令碼資源是最明顯的安全性風險,但 CSP 提供了
可以更精細地控管資源的政策指令
允許載入網頁您已看過 script-src
,這個概念
都應該清晰可辨
我們來快速示範其餘的資源指令下列清單 代表指令在等級 2 的狀態。已發布第 3 級規格,但卻在主要規格尚未實作 。
base-uri
可限制網頁可在<base>
元素中顯示的網址。child-src
列出 worker 和內嵌影格內容的網址。適用對象 範例:child-src https://youtube.com
會啟用以下來源的嵌入影片: YouTube 而非其他來源。connect-src
會限制可以連線的來源 (透過 XHR、 WebSockets 和 EventSource)。font-src
會指定可提供網路字型的來源。Google 網路 您可以透過font-src https://themes.googleusercontent.com
啟用字型。form-action
列出可從<form>
標記提交的有效端點。frame-ancestors
會指定可嵌入目前網頁的來源。 這個指令適用於<frame>
、<iframe>
、<embed>
和<applet>
標記。 這個指令無法用於<meta>
標記,而且只會套用至非 HTML 再複習一下,機構節點 是所有 Google Cloud Platform 資源的根節點frame-src
已在第 2 級淘汰,但在第 3 級已還原。如果不是 表示現在仍可像過去一樣改回child-src
。img-src
定義可載入圖片的來源。media-src
會限制能放送影片和音訊的來源。object-src
可控制 Flash 和其他外掛程式。plugin-types
會限制網頁可叫用的外掛程式類型。report-uri
會指定瀏覽器在發生 違反內容安全政策。無法在<meta>
中使用這個指令 標記內。- 「
style-src
」是樣式表的script-src
對應項目。 upgrade-insecure-requests
會指示使用者代理程式重新編寫網址配置。 將 HTTP 變更為 HTTPS這項指令適用於含有大量 需要重寫的舊網址worker-src
是 CSP 級別 3 指令,用來限制可能 顯示為工作站、共用工作站或 Service Worker。截至 2017 年 7 月為止 指令包含 有限實作。
指令預設為公開。假設您沒有為
指令後,假設 font-src
,則該指令的預設行為為
但已指定 *
做為有效來源 (例如
不受限制)。
您可以指定 default-src
來覆寫這個預設行為
指令。這個指令會定義
未指定的指令一般而言,這適用於
結尾是 -src
。如果將 default-src
設為 https://example.com
,而您失敗
指定 font-src
指令,然後從中載入字型
https://example.com
,不包含在其他位置。我們在script-src
也就是圖片、字型等內容
與任何來源有關
下列指令不會使用 default-src
做為備用方案。注意事項
未設定,就和允許任何項目一樣
base-uri
form-action
frame-ancestors
plugin-types
report-uri
sandbox
您可以根據自己的需求,使用多少指令來測試這些指令
只要在 HTTP 標頭中列出每個應用程式,
指令中加上分號確認已列出全部
在 single 指令中定義特定類型的必要資源。如果您寫入
例如 script-src https://host1.com; script-src https://host2.com
就會直接忽略第二個指令如下所示
正確指定兩個來源為有效來源:
script-src https://host1.com https://host2.com
舉例來說,假設您的應用程式從某個伺服器載入所有資源
內容傳遞網路 (例如 https://cdn.example.net
) 並知悉您
不含任何頁框內容或外掛程式,你的政策看起來可能會像
如下所示:
Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'
實作詳情
您會看到 X-WebKit-CSP
和 X-Content-Security-Policy
各種標題
線上教學課程日後請忽略這些前置字元
標題。新版瀏覽器 (IE 除外) 支援無前置字串的
Content-Security-Policy
標頭。這正是應使用的標頭。
無論您使用何種標頭,政策都是逐頁定義: 您必須將 HTTP 標頭連同每個想分享的回應 才能受到妥善保護這個功能提供許多彈性 根據特定需求修正特定網頁的政策也許一組 你的網站上有 +1 按鈕,有些則不允許:你可以允許 按鈕程式碼,只有在必要時才載入。
每個指令中的來源清單都是彈性的。如要指定來源
配置 (data:
、https:
),或特定程度的範圍 (僅限主機名稱)
(example.com
,與該主機上的任何來源相符:任何配置、任何通訊埠) 到
完整 URI (https://example.com:443
,只與 HTTPS 相符,
example.com
,且只有通訊埠 443)。系統接受萬用字元 (但僅限於配置)
通訊埠,或是主機名稱的最左側位置:*://*.example.com:*
會
符合 example.com
的所有子網域 (但「不是」example.com
本身),使用
和任何通訊協定都一樣
來源清單也接受四個關鍵字:
- 正如您所預期的一樣,
'none'
不會進行比對。 'self'
與目前的來源相符,但與子網域的子網域不相符。'unsafe-inline'
允許內嵌 JavaScript 和 CSS,(我們將在 更多細節)。'unsafe-eval'
允許eval
等文字轉 JavaScript 機制。(我們會 )
這些關鍵字需要單引號。例如 script-src 'self'
(含引號)
授權從目前主機執行 JavaScript;script-src self
(無引號) 允許從名為「self
」的伺服器執行 JavaScript(而不是從
這可能不是您想要的結果
沙箱機制
還有一個指令值得討論:sandbox
。有點麻煩
和我們討論的比較項目不同,因為會限制使用者執行
不會超過網頁可載入的資源如果
如果有 sandbox
指令,系統會將網頁視為已載入
在含有 sandbox
屬性的 <iframe>
內。模型可以提供多種
這會影響網頁的影響:強制網頁成為專屬來源,並阻止表單產生
以及其他可能性這有點不在本文的討論範圍內
如需有效沙箱屬性的完整資訊,請參閱
「採用沙箱機制」一節。
中繼標記
CSP 的偏好傳送機制是 HTTP 標頭。這項服務很實用
直接在標記中設定網頁政策。方法是使用 <meta>
標記搭配
http-equiv
屬性:
<meta
http-equiv="Content-Security-Policy"
content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>
無法用於 frame-ancestors
、report-uri
或 sandbox
。
內嵌程式碼視為有害
但應清楚指出 CSP 是以許可清單來源為基礎,因為這是
指示瀏覽器以明確的方式處理特定資源組合
並拒絕其餘的部分來源式許可清單不適用
然而,必須解決 XSS 攻擊所造成的最大威脅:內嵌指令碼插入。
如果攻擊者能夠插入直接含有部分惡意內容的指令碼標記
酬載 (<script>sendMyDataToEvilDotCom();</script>
),
瀏覽器並沒有用來區分
內嵌指令碼標記。CSP 可以完全停用內嵌指令碼,藉此解決這個問題:
只有這是唯一的方式
這個停權設定不僅包含直接內嵌於 script
標記的指令碼,也包括
內嵌事件處理常式和 javascript:
網址。您需要將
將 script
標記新增至外部檔案,並將 javascript:
網址和 <a ... onclick="[JAVASCRIPT]">
替換為適當的 addEventListener()
呼叫。例如:
您或許可以改寫以下內容:
<script>
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
</script>
<button onclick="doAmazingThings();">Am I amazing?</button>
例如:
<!-- amazing.html -->
<script src="amazing.js"></script>
<button id="amazing">Am I amazing?</button>
<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('amazing').addEventListener('click', doAmazingThings);
});
重寫的程式碼有好多優勢,無法充分發揮 CSP;無論您是否使用 CSP,都是最佳做法。內嵌 JavaScript 會以您不想要的方式混用結構和行為。 外部資源讓瀏覽器更容易快取,也更容易理解 進而編譯和壓縮你寫得更好 程式碼。
內嵌樣式的處理方式相同:style
屬性和 style
標記應合併為外部樣式表,以避免發生
有很多巧妙
而是運用 CSS 供應商
實現的資料竊取方法
如果必須使用內嵌指令碼和樣式,可以啟用
,將 'unsafe-inline'
新增為 script-src
或 style-src
中的允許來源
指令。您也可以使用 Nonce 或雜湊 (請見下方說明)。
控管 In-Line 指令碼是 CSP 提供最大的安全性優勢。
同樣地,禁止使用內嵌樣式也會強化應用程式。編碼器-解碼器架構
事先確保所有程式碼在移動所有程式碼後能正常運作
但這才是值得做出的取捨
如果您一定要用到
CSP 級別 2 可讓您執行下列操作,為內嵌指令碼提供回溯相容性: 使用密碼編譯 Nonce (數字) 將特定內嵌指令碼加入許可清單 一次使用一次) 或雜湊雖然這可能相當麻煩,但很實用 順便一按
如要使用 Nonce,請為指令碼標記提供 Nonce 屬性。它的值必須與一個 並在信任來源清單中找到您。例如:
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// Some inline code I can't remove yet, but need to asap.
</script>
現在,請將 Nonce 附加至 nonce-
關鍵字。script-src
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
請注意,每次網頁要求都必須重新產生 Nonce,且 不可猜測
「雜湊」的運作方式大同小異。您不需要將程式碼加進指令碼標記
建立指令碼的 SHA 雜湊,並新增至 script-src
指令。
舉例來說,假設您的網頁包含:
<script>
alert('Hello, world.');
</script>
您的政策會包含以下內容:
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
這裡有幾點要注意。sha*-
前置字串可指定演算法
來產生雜湊值在上述範例中,使用了 sha256-
。CSP 也
支援 sha384-
和 sha512-
。產生雜湊時,請勿包含
<script>
標記。此外,大小寫和空白字元也包括開頭或
在結尾處的空白字元
運用產生 SHA 雜湊的 Google 搜尋,將導向所有解決方案 在 Chrome 40 以上版本中,請開啟開發人員工具,然後 重新載入網頁。「Console」分頁中會顯示錯誤訊息和正確資訊 每個內嵌指令碼的 sha256 雜湊值。
一併評估
即使攻擊者無法直接插入指令碼,他們也許可以
您的應用程式轉換為可執行的 JavaScript
並代表他們執行該工作eval()
,新討論串
Function()、setTimeout([string], ...)
和
setInterval([string], ...)
都是所有插入的向量
進而執行意想不到的惡意內容CSP 的預設
才能完全封鎖這些向量。
這對建構應用程式的方式的影響不只部分:
- 您必須透過內建的
JSON.parse
剖析 JSON,而非依賴eval
。您可以在 才能確保安全性 - 重新編寫目前正在進行的任何
setTimeout
或setInterval
呼叫 以內嵌函式 (而非字串) 取代例如:
setTimeout("document.querySelector('a').style.display = 'none';", 10);
這樣寫得好:
setTimeout(function () {
document.querySelector('a').style.display = 'none';
}, 10);
- 避免在執行階段使用內嵌範本:許多範本程式庫會盡量使用
new Function()
,在執行階段加速產生範本。這是 應用動態程式設計的巧妙運用,卻有可能導致 評估惡意文字部分架構支援立即可用的 CSP, 在沒有eval
的情況下,會改回使用完善的剖析器。 AngularJS 的 ng-csp 指令 就是個好例子
但更理想的做法是
預先編譯 (帳號代碼確實、
。預先編譯範本可大幅改善使用者體驗
執行階段導入速度更快,而且安全。如果 eval 和
文字轉 JavaScript - 對應用程式至關重要
將 'unsafe-eval'
新增為 script-src
中的允許來源,即可啟用這些元件
指令,但我們強烈建議不要這麼做。禁止執行
字串讓攻擊者更難執行未經授權的操作
導入大量程式碼
報表
CSP 能夠封鎖不受信任的資源,在用戶端對
但利用這種模式
會傳回至伺服器,方便您找出所有可能產生
避免惡意插入惡意內容為此,您可以指示
瀏覽器匯出至 POST
JSON 格式的違規報告,回報為一個位置
在 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"
}
}
這提供了大量資訊
具體原因,包括違規網頁
發生 (document-uri
),該網頁的參照網址 (請注意,與 HTTP
標頭欄位,金鑰「沒有」拼字錯誤),表示該資源違反
網頁的政策 (blocked-uri
),也就是網頁違反的具體指令
(violated-directive
) 和網頁的完整政策 (original-policy
)。
報表專用
如果您才剛開始使用 CSP,可以評估目前的
瞭解應用程式狀態,再向使用者推出圖像政策。
為了逐步完成部署作業,您可以要求瀏覽器
並檢舉違規行為,但不強制執行限制。而不是
傳送 Content-Security-Policy
標頭,則傳送
Content-Security-Policy-Report-Only
標頭。
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
在「報表專用」模式中指定的政策不會封鎖受限制的資源,但 它會將違規報表寄到您指定的地區。您甚至可以 同時強制執行一項政策,同時監控另一個政策。太棒了 可評估應用程式的 CSP 變更所造成的影響:開啟 檢舉新政策、監控違規檢舉,並修正 調高;等一切沒問題後,就可以開始強制執行新政策。
實際使用情況
CSP 1 可在 Chrome、Safari 和 Firefox 中使用,但功能有限 支援 IE 10。你可以 查看 caniuse.com 的詳細資訊。CSP 等級 2 自從 Chrome 開始於 Chrome 推出 第 40 版。像 Twitter 和 Facebook 等大型網站都已部署標題 (Twitter 的個案研究值得一讀),相關標準也非常準備就緒 讓您開始在自家網站上部署
制定應用程式政策的第一步,就是評估 查看實際載入的資源確定自己對 以及設定相關的政策 Google Cloud 就是最佳選擇以下我們將逐一介紹幾個常見用途 而他們最好能在 CSP 的保護範圍內予以支援。
用途 1:社群媒體小工具
Google 的 +1 按鈕 含有
https://apis.google.com
的指令碼,並嵌入了<iframe>
的https://plusone.google.com
。您需要一個同時包含這兩者的政策 字串內,才能嵌入按鈕。最低政策為script-src https://apis.google.com; child-src https://plusone.google.com
。您也需要 確保 Google 提供的 JavaScript 程式碼片段能擷取至 外部 JavaScript 檔案如果您已使用frame-src
套用第 1 級政策 第 2 級需要您將其變更為child-src
。不再需要這項操作 第 3 級Facebook 的喜歡按鈕 提供多種實作選項建議您繼續使用
<iframe>
版本,因為該版本會與您網站的其他部分安全採用沙箱機制。這項服務 需要child-src https://facebook.com
指令才能正常運作。注意事項 在預設情況下,Facebook 提供的<iframe>
程式碼會載入相對 網址://facebook.com
。請將 變更為明確指定 HTTPS:https://facebook.com
。如果您沒有需要,也可以使用 HTTP。Twitter 的推文按鈕 必須透過存取指令碼和影格,兩者都是由
https://platform.twitter.com
。(Twitter 也會透過 default;請編輯程式碼,在複製/貼上本機檔案時指定 HTTPS)。 只要移動 JavaScript 程式碼片段,即可透過script-src https://platform.twitter.com; child-src https://platform.twitter.com
完成 提供給外部 JavaScript 檔案的網址其他平台的規定類似,也能採取類似的處理方式。 建議您只將
default-src
設為'none'
,然後觀察控制台 然後決定需啟用哪些資源,小工具才能正常運作。
加入多個小工具的方法相當簡單明瞭:只要結合政策 指令,記得將同一類型的所有資源合併成單一 指令。如果想要全部三個社群媒體小工具,政策: 輸入:
script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com
用途 2:鎖定
假設您經營銀行網站的某段時間能夠確保
只能載入您自己編寫的資源。在這個情境中
從封鎖所有內容 (default-src 'none'
) 的預設政策開始,然後再從該政策開始建構。
假設銀行從 CDN 載入所有圖片、樣式和指令碼
https://cdn.mybank.net
,並透過 XHR 連線至 https://api.mybank.com/
到
會將許多位元的資料拆下使用頁框,但僅適用於
網站 (無第三方來源)。網站上沒有 Flash,也沒有字型,也沒有
額外項目。以下是我們可傳送的最嚴格 CSP 標頭:
Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'
用途 3:僅限 SSL
一場婚禮討論論壇管理員想確保所有資源都投入 只透過安全管道載入,但不太撰寫太多程式碼。重新編寫 第三方論壇軟體的大量程式碼 內嵌指令碼和樣式超乎想像。下列政策會是 有效:
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
雖然 https:
已在 default-src
中指定,但指令碼和樣式
指令不會自動繼承該來源。每項指令
會覆寫該特定資源類型的預設值。
未來
內容安全政策第 2 級為 候選建議。W3C 的 Web 應用程式安全性工作小組 已經開始進行規範的下個疊代作業 內容安全政策第 3 級。
如果你有興趣瞭解這些即將推出的功能 略過 public-websec@ 郵寄清單封存封存檔, 或自己加入。