內容安全政策 (CSP) 不破壞網站指南
您聽說過內容安全政策 (CSP) 對於保護網站免受跨站腳本 (XSS) 和資料注入攻擊至關重要。但當您嘗試加入時,網站卻壞了:圖片消失、腳本停止執行、樣式不見。感覺像是在安全性和功能性之間取捨。其實不必如此。
在本指南中,您將學習一種實用、逐步的方法來部署 CSP 而不破壞網站。我們將涵蓋核心指令、如何使用 nonce 和 hash,以及如何安全地測試。最後,您將擁有一個能增強安全性而不犧牲使用者體驗的 CSP。
什麼是 CSP,為何會破壞網站?
內容安全政策是一種瀏覽器安全標準,讓您限制頁面上可以載入哪些資源(腳本、樣式、圖片、字型等)。它透過 HTTP 標頭傳遞,例如 Content-Security-Policy: default-src 'self'。
CSP 會破壞網站,因為它會封鎖任何不符合您政策的資源。如果您有內聯腳本、來自 CDN 的外部腳本或內聯樣式,除非明確允許,否則它們都會被封鎖。預設行為是封鎖所有不允許的內容,這就是為什麼嚴格的政策可能很快破壞網站。
關鍵是從寬鬆的政策開始,並在監控違規情況的同時逐步收緊。
您需要了解的核心 CSP 指令
CSP 使用指令來控制不同的資源類型。以下是最常見的:
- default-src:其他指令的後備。從這裡開始。
- script-src:控制 JavaScript 來源。
- style-src:控制 CSS 來源。
- img-src:控制圖片來源。
- connect-src:控制 AJAX、WebSocket 和 fetch 目標。
- font-src:控制網頁字型來源。
- frame-src:控制 iframe 來源。
- report-uri / report-to:發送違規報告的位置。
您可以在一個標頭中設定多個指令,以分號分隔。例如:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://images.example.com
每個指令接受以空格分隔的來源列表。來源可以是關鍵字如 'self'、'unsafe-inline'、'unsafe-eval',或 URL,或 nonce/hash。
逐步指南:部署 CSP 而不破壞網站
遵循以下步驟安全地推出 CSP。
- 從僅報告政策開始。 使用
Content-Security-Policy-Report-Only標頭,而非強制執行的標頭。這讓您看到什麼會被封鎖,而不實際封鎖。 - 設定寬鬆政策。 從類似
default-src 'self' 'unsafe-inline' 'unsafe-eval' https:開始,允許大多數內容。這能最小化破壞。 - 收集違規報告。 設定
report-uri指向記錄違規的端點。檢閱這些報告以識別被封鎖的資源。 - 修復違規。 更新您的程式碼以避免內聯腳本/樣式,或加入 nonce/hash。將外部資源移至允許的網域。
- 逐步收緊政策。 重構後移除
'unsafe-inline'和'unsafe-eval'。縮小允許的網域。 - 切換到強制執行模式。 一旦報告顯示沒有意外封鎖,將標頭改為
Content-Security-Policy(不含-Report-Only)。 - 持續監控。 保持報告端點活躍以捕捉新問題。
這種漸進式方法確保您在提升安全性的同時不會破壞網站。
為內聯腳本使用 Nonce 和 Hash
內聯腳本是 CSP 破壞的常見原因。與其允許 'unsafe-inline',不如使用 nonce(一次性數字)或 hash。
Nonce 方法: 為每個請求生成隨機 nonce,加入您的 CSP 標頭,並包含在您的 script 標籤中。
Content-Security-Policy: script-src 'nonce-abc123'
<script nonce="abc123">...</script>
Hash 方法: 計算內聯腳本的 SHA hash 並加入政策。
Content-Security-Policy: script-src 'sha256-xyz...'
Hash 最適合不常變更的靜態內聯腳本。Nonce 則更適合動態內容。
對於樣式,您也可以使用 nonce 或 hash,但請注意,帶有 nonce 的 style-src 不涵蓋內聯樣式屬性(例如 style="...")。對於這些,您需要 'unsafe-inline' 或重構為類別。
常見 CSP 指令及其影響
| 指令 | 控制內容 | 常見來源 |
|---|---|---|
| default-src | 所有資源類型的後備 | 'self', https: |
| script-src | JavaScript 來源 | 'self', 'nonce-...', 'sha256-...', https://cdn.com |
| style-src | CSS 來源 | 'self', 'unsafe-inline', 'nonce-...' |
| img-src | 圖片來源 | 'self', data:, https://images.com |
| connect-src | AJAX、WebSocket、fetch | 'self', https://api.com |
| font-src | 網頁字型 | 'self', https://fonts.gstatic.com |
| frame-src | Iframes | 'self', https://youtube.com |
在建立政策時,將此表作為快速參考。
測試和監控您的 CSP
在強制執行之前,徹底測試。使用瀏覽器開發者工具:Console 標籤會將 CSP 違規顯示為錯誤。Network 標籤顯示 CSP 標頭。
對於自動化測試,考慮使用 Google 的 CSP Evaluator(線上)或 csp_evaluator npm 套件等工具。這些有助於識別弱政策。
設定報告端點以在生產環境中收集違規。您可以使用 Report URI 等服務,或建立自己的端點記錄到檔案或資料庫。定期分析報告以捕捉新問題。
記住:CSP 不是萬靈丹。它是一層防禦。將其與輸入驗證、輸出編碼和其他安全最佳實踐結合使用。
常見問題
Content-Security-Policy 和 Content-Security-Policy-Report-Only 有什麼區別?
強制執行標頭 (Content-Security-Policy) 會封鎖違規。僅報告標頭 (Content-Security-Policy-Report-Only) 只報告違規而不封鎖,讓您安全地測試政策。
我可以將 CSP 與 onclick 等內聯事件處理程序一起使用嗎?
不行,內聯事件處理程序會被 CSP 封鎖,除非您使用 'unsafe-inline'(不建議)或重構為使用 addEventListener。為了更好的安全性,避免內聯事件處理程序。
如何使用 CSP 允許 Google Analytics?
將 Google Analytics 網域加入您的 script-src 和 connect-src 指令。例如:script-src 'self' https://www.googletagmanager.com; connect-src 'self' https://www.google-analytics.com。查看 Google 的文件以了解最新要求。
部署 CSP 不必是一個痛苦的過程。透過漸進式方法,您可以保護使用者免受 XSS 和其他攻擊,而不會中斷網站。從僅報告模式開始,修復違規,並隨著時間收緊政策。
如果您需要快速格式化或驗證 CSP 報告的 JSON 設定檔,試試我們的 JSON Formatter 來美化和除錯您的 JSON 資料。