內容安全策略 (CSP) 的實現

Content-Security-Policy HTTP 標頭提供了對網站可載入程式碼及其允許執行的操作的精細控制。

問題

本文主要關注的焦點是跨站指令碼 (XSS) 攻擊。這些攻擊通常是由於缺乏對網站資源載入來源的控制和意識所致。隨著網站變得越來越龐大和複雜,並且越來越依賴 JavaScript 庫等第三方資源,這一問題也變得更難管理。

注意: CSP 是保護免受 XSS 攻擊的完整策略的一部分。還有其他因素也同樣重要,例如 輸出編碼清理

CSP 還可以幫助修復其他問題,這些問題將在其他文章中介紹

  • 透過阻止您的網站嵌入到 <iframe> 元素中來 防止點選劫持。這可以透過 CSP 的 frame-ancestors 指令來實現。
  • 透過將任何 HTTP 連線升級到 HTTPS 來 防止中間人 (MiTM) 攻擊。CSP 的 upgrade-insecure-requests 指令對此有所幫助。請參閱 升級不安全請求

解決方案

實現 嚴格 CSP 是利用 CSP 緩解 XSS 漏洞的最佳方法。它使用基於 nonce 或 hash 的獲取指令,以確保只有包含正確 nonce 或 hash 的指令碼和/或樣式才能執行。駭客插入的 JavaScript 將無法執行。

嚴格 CSP 還

  • 停用不安全的 內聯 JavaScript 的使用,這意味著內聯 事件處理程式屬性(如 onclick)的用法。這可以防止不正確轉義的使用者輸入被 Web 瀏覽器解釋為 JavaScript。
  • 停用 有風險的 API 呼叫(如 eval()的使用,這是 script-src 指令的另一個效果。
  • 透過 object-src 'none' 停用所有物件嵌入。
  • 透過 base-uri 'none'; 停用 <base> 元素的用法來設定基本 URI。

與基於位置的策略(也稱為允許列表策略,即您指定指令碼可以從哪些域執行)相比,嚴格 CSP 更受青睞。這是因為允許列表策略最終經常允許不安全的域,這違背了擁有 CSP 的初衷,而且它們可能變得非常龐大和難以管理,特別是如果您試圖允許需要大量第三方指令碼才能正常執行的服務。

實施 CSP 的步驟

實施嚴格 CSP,然後開始精確定位因該策略而載入失敗的資源,並採取措施來解決這些問題。

注意: 在使用 Content-Security-Policy 標頭實施任何實際的 CSP 之前,建議您先使用 Content-Security-Policy-Report-Only HTTP 標頭進行測試;請參閱下方的 報告模式 CSP

  1. 決定是使用 nonces 還是 hashes。如果您可以動態生成內容,則應使用 nonces;如果您需要提供靜態內容,則應使用 hashes。
  2. 按照 解決方案 部分的概述實施嚴格 CSP。確保您想要執行的外部和內部指令碼(透過 <script> 元素包含)在伺服器上已將其正確的 nonce 插入到 nonce 屬性中。如果您改用 hashes,則外部指令碼應將正確的 hash 插入到 integrity 屬性中。
  3. 如果允許的指令碼繼續載入第三方指令碼,這些指令碼將無法載入,因為它們沒有所需的 nonce 或 hash。透過新增 strict-dynamic 指令來解決此問題,該指令使第一個指令碼載入的指令碼具有相同的信任級別,而無需顯式提供 nonce 或 hash。
  4. 重構嚴格 CSP 所不允許的模式,例如內聯事件處理程式和 eval()。例如,將內聯事件處理程式替換為指令碼內的 addEventListener() 呼叫。
  5. 除非網站需要嵌入能力,否則應使用 object-src 'none' 停用其執行。
  6. 如果您無法刪除 eval() 的用法,可以將 unsafe-eval 關鍵字新增到您的嚴格 CSP 中以允許它們,儘管這會大大削弱 CSP 的安全性。
  7. 如果您無法刪除事件處理程式屬性,可以將 unsafe-hashes 關鍵字新增到您的嚴格 CSP 中以允許它們。這在一定程度上不安全,但比允許所有內聯 JavaScript 安全得多。

如果您無法使嚴格 CSP 生效,基於允許列表的 CSP 比沒有 CSP 要好得多,像 default-src https: 這樣的 CSP 仍然提供了一些保護,停用了不安全的內聯/eval(),並且只允許透過 HTTPS 載入資源(影像、字型、指令碼等)。

警告: 如果可能,請避免在 CSP 中包含不安全的來源。例如:

  • unsafe-inline.
  • script-srcobject-srcdefault-src 中的 data: URI。
  • 過於寬泛的來源或表單提交目標。

如果您無法使用 Content-Security-Policy 標頭,頁面可以改用 <meta http-equiv="Content-Security-Policy" content="…"> 元素。這應該是文件 <head> 中的第一個 <meta> 元素。

報告模式 CSP

在使用 Content-Security-Policy 標頭實施任何實際的 CSP 之前,建議您先使用 Content-Security-Policy-Report-Only HTTP 標頭進行測試。這使您能夠檢視使用該策略是否會發生任何違規行為。

網站應使用 report-toreport-uri 報告指令。這些指令會導致瀏覽器將關於 CSP 違規的 JSON 報告 POST 到端點(在 report-to 的情況下,在 Reporting-Endpoints 標頭中指定)。這使得 CSP 違規能夠被快速捕獲和修復。

注意: report-to 指令比已棄用的 report-uri 指令更受推薦。但是,兩者仍然是必需的,因為 report-to 尚未獲得完整的跨瀏覽器支援。

另見