確保 CSP 能有效防範 XSS 攻擊

內容安全政策 (CSP) 有助於確保網站擁有者信任網頁中載入的任何內容。CSP 可以減少跨網站指令碼攻擊 (XSS) 攻擊,因為攻擊者可以封鎖攻擊者插入的不安全指令碼。不過,如果 CSP 不夠嚴格,也可以輕鬆略過。詳情請參閱運用嚴格的內容安全政策 (CSP) 限制跨網站指令碼攻擊 (XSS)。Lighthouse 會收集主要文件強制執行的 CSP,並回報 CSP Evaluator (如果可以略過) 的問題。

Lighthouse 報告警告,在強制執行模式下找不到 CSP。
Lighthouse 報告警告,無法在強制執行模式下找到 CSP。

不可略過的 CSP 必要做法

請採用下列做法,確保系統無法略過 CSP。如果可以略過 CSP,Lighthouse 就會發出高嚴重性的警告。

CSP 鎖定 XSS

如要指定 XSS,CSP 應包含 script-srcobject-srcbase-uri 指令。CSP 中也不應出現語法錯誤。

script-srcobject-src 分別可保護網頁,防範不安全的指令碼和不安全的外掛程式。或者,您可以使用 default-src 設定廣泛的政策,取代許多指令,包括 script-srcobject-src

base-uri 可防止在未經授權的情況下插入未經授權的 <base> 標記,這些標記可用於將所有相對網址 (例如指令碼) 重新導向至攻擊者控制的網域。

CSP 會使用 Nonce 或 Hash 避免許可清單略過

script-src 設定許可清單的 CSP 會假設所有來自信任網域的回應都安全無虞,且可以做為指令碼執行。不過,這項假設不適用於新型應用程式;一些常見的良性模式 (例如公開 JSONP 介面AngularJS 程式庫的託管副本),可讓攻擊者規避 CSP 的限制。

在實務上,雖然應用程式作者可能認為其中較不明顯,但有 XSS 錯誤的攻擊者可以規避大多數的 script-src 許可清單,幾乎沒有辦法防範指令碼插入。相較之下,以 Nonce 和雜湊為基礎的方法不會遭到這類問題,因此更容易採用及維護更安全的政策。

舉例來說,以下程式碼會使用託管於信任網域的 JSONP 端點,插入攻擊者控制的指令碼:

CSP:

script-src https://trusted.example.com

HTML:

<script src="https://trusted.example.com/path/jsonp?callback=alert(document.domain)//"></script>

為了避免遭到略過,CSP 應允許個別使用 Nonce 或雜湊的指令碼,並使用「strict-dynamic」而非許可清單。

安全 CSP 的其他建議

實作下列做法以提高安全性和相容性。如果 CSP 未遵循其中一項建議,Lighthouse 就會發出中嚴重性的警告。

設定 CSP 報告

設定回報目的地有助於監控任何故障情形。您可以使用 report-urireport-to 指令設定回報目的地。部分新式瀏覽器目前不支援 report-to,因此建議您同時使用,或只使用 report-uri

如有任何內容違反 CSP,瀏覽器會將報告傳送至設定的到達網頁。請確認您已在這個目的地中設定應用程式,以便處理這些報表。

在 HTTP 標頭中定義 CSP

您可以在中繼標記內定義 CSP,如下所示:

<meta http-equiv="Content-Security-Policy" content="script-src 'none'">

不過,如果可以,請在 HTTP 回應標頭中定義 CSP。中繼標記之前插入會略過 CSP。此外,CSP 中繼標記不支援 frame-ancestorssandbox 和報表功能。

確保 CSP 與舊版相容

並非所有瀏覽器都支援 CSP Nonce/Hash,因此建議將 unsafe-inline 新增為不符規定瀏覽器的備用選項。如果瀏覽器支援 Nonce/Hash,系統就會忽略 unsafe-inline

同樣地,所有瀏覽器都不支援 strict-dynamic。建議您將許可清單設為所有不相容瀏覽器的備用清單。系統會在支援 strict-dynamic 的瀏覽器中忽略許可清單。

如何開發嚴格 CSP

以下範例說明如何搭配採用 Nonce 政策的嚴格 CSP。

CSP:

script-src 'nonce-random123' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none';
report-uri https://reporting.example.com;

HTML:

<script nonce="random123" src="https://trusted.example.com/trusted_script.js"></script>

random123 可以是每次載入網頁時在伺服器端產生的任何 Base64 字串。新型瀏覽器會忽略 unsafe-inlinehttps:,因為 Nonce 和 strict-dynamic。如要進一步瞭解如何採用嚴格的 CSP,請參閱嚴格 CSP 指南

您可以使用 Lighthouse 和 CSP Evaluator,檢查 CSP 是否有可能的略過項目。如要在不破壞現有網頁的情況下測試新的 CSP,請將 Content-Security-Policy-Report-Only 做為標頭名稱,在報表專用模式中定義 CSP。這會將 CSP 違規事項傳送到您使用 report-toreport-uri 設定的任何報表目的地,但不會實際強制執行 CSP。