確保 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 或雜湊,避免許可清單略過許可清單

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

以下示例說明如何使用嚴格 CSP 搭配 Nonce 政策。

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 字串。由於 Nonce 和 strict-dynamic,新版瀏覽器會忽略 unsafe-inlinehttps:。如要進一步瞭解如何採用嚴格 CSP,請參閱 Strict CSP 指南

您可以使用 Lighthouse 和 CSP Evaluator 檢查 CSP 是否可能略過。如果想測試新的 CSP,但不想中斷現有網頁的風險,請使用 Content-Security-Policy-Report-Only 做為標頭名稱,在報表專用模式中定義 CSP。這項操作會將違反 CSP 規定的內容傳送至您使用 report-toreport-uri 設定的所有報表目的地,但不會實際強制執行 CSP。