目錄
什麼是 CSP?
Content Security Policy(CSP)是一種 HTTP 回應標頭,用於告訴瀏覽器哪些外部資源可以載入到網頁中。這是一種多層式資安防禦機制,能有效防止跨網站指令碼攻擊(XSS)、點擊劫持(Clickjacking)和其他程式碼注入攻擊。
CSP 由網站伺服器透過 HTTP 標頭或 HTML 的 <meta> 標籤傳遞給瀏覽器,瀏覽器則會根據這些規則決定是否允許載入各類資源。
為什麼需要 CSP?
傳統的網站安全主要依賴伺服器端驗證,但攻擊者仍有辦法繞過這些防護。CSP 的核心價值在於:
- 防止 XSS 攻擊:限制指令碼來源,阻止未授權的 JavaScript 執行
- 防止資料外洩:控制 AJAX、Fetch、WebSocket 等連線的目標網域
- 防止點擊劫持:透過 frame-ancestors 防止網站被嵌入惡意網頁
- 減少 Mixed Content 問題:確保所有資源都透過 HTTPS 載入
CSP 如何運作?
CSP 的運作方式很直觀:伺服器傳送一個包含政策規則的 HTTP 標頭,瀏覽器則會解析這些規則並據此過濾內容。當瀏覽器遇到違反 CSP 的情況時,會在控制台產生警告(預設模式)或完全阻擋資源(強制模式)。
基本的 CSP 語法如下:
Content-Security-Policy: directive1 source1; directive2 source2例如:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'CSP 指令詳解
主要指令
| 指令 | 說明 |
|---|---|
default-src | 預設來源策略,用於未指定指令的資源類型 |
script-src | 控制 JavaScript 檔案的來源 |
style-src | 控制 CSS 樣式表的來源 |
img-src | 控制圖片資源的來源 |
font-src | 控制字體檔案的來源 |
connect-src | 控制 AJAX、Fetch、WebSocket 的連線目標 |
media-src | 控制音訊和視訊資源的來源 |
object-src | 控制 <object>、<embed>、<applet> 等外掛程式 |
frame-src | 控制 <iframe> 和 <frame> 的來源(舊版為 child-src) |
frame-ancestors | 指定哪些網頁可以嵌入當前頁面(用於防止點擊劫持) |
form-action | 限制表單提交的目標網域 |
base-uri | 控制 <base> 標籤的 URL |
upgrade-insecure-requests | 自動將 HTTP 請求升級為 HTTPS |
特殊關鍵字
'self':允許來自同源的資源'none':禁止所有來源'unsafe-inline':允許內聯指令碼或樣式(不安全)'unsafe-eval':允許 eval() 等動態程式碼執行(不安全)'nonce-xxx':只允許具有特定隨機數的內聯指令碼'hash-xxx':只允許特定雜湊值的內聯指令碼
常見設定範例
基本嚴格模式
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'允許 CDN 資源
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com https://ajax.googleapis.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https://*.cloudflare.com; font-src 'self' https://fonts.gstatic.com允許 Google Analytics
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.google-analytics.com https://www.googletagmanager.com; connect-src 'self' https://www.google-analytics.com只允許 HTTPS
Content-Security-Policy: default-src 'self'; upgrade-insecure-requestsCSP 與 X-Frame-Options 差異
很多人會問:CSP 的 frame-ancestors 和傳統的 X-Frame-Options 有什麼不同?
| 特性 | CSP frame-ancestors | X-Frame-Options |
|---|---|---|
| 語法彈性 | 支援多個來源、萬用字元、CORS | 只支援 DENY、SAMEORIGIN、ALLOW-FROM |
| 多網域設定 | 可同時允許多個網域 | 僅支援單一網域(ALLOW-FROM 支援度低) |
| 瀏覽器支援 | 現代瀏覽器全面支援 | 舊版瀏覽器支援度有限 |
| 回退機制 | 無瀏覽器支援時會靜默失效 | 部分瀏覽器會忽略 |
| 功能性 | 可控制 iframe 嵌入還能控制其他資源 | 僅能防止點擊劫持 |
差異說明
X-Frame-Options 是早期的解決方案,語法簡單但彈性不足。例如:
X-Frame-Options: DENYX-Frame-Options: SAMEORIGINX-Frame-Options: ALLOW-FROM https://example.comCSP frame-ancestors 是更現代的解決方案:
Content-Security-Policy: frame-ancestors 'self' https://trusted-site.com https://cdn.example.com實際上,CSP frame-ancestors 是設計用來取代 X-Frame-Options 的。如果您需要同時支援舊版瀏覽器,可以兩者都設置;但在現代環境中,建議使用 CSP frame-ancestors。
多來源設定實作
在實際應用中,網站通常需要從多個來源載入資源。CSP 支援多種方式來設定多個來源:
方式一:直接列出多個網域
Content-Security-Policy: script-src 'self' https://cdn.example.com https://ajax.googleapis.com https://www.googletagmanager.com方式二:使用萬用字元
Content-Security-Policy: img-src 'self' https://*.cloudflare.com https://*.akamai.com萬用字元可以匹配子網域,例如 *.example.com 會允許 cdn.example.com、api.example.com 等。
方式三:使用資料 URI
Content-Security-Policy: img-src 'self' data: https://example.comdata: 允許以 Base64 編碼的內聯圖片。
方式四:結合多個條件
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123' https://cdn.example.com; style-src 'self' 'self' https://fonts.googleapis.com; img-src 'self' data: https://*.cloudflare.com; frame-ancestors 'self' https://trusted-partner.com;方式五:使用 report-uri 監控違規
Content-Security-Policy: default-src 'self'; report-uri https://example.com/csp-report當發生 CSP 違規時,瀏覽器會自動將詳細資料 POST 到指定的 URL,方便開發者監控和調整政策。
結論
CSP 是現代網站安全不可或缺的一環。透過正確設定 CSP 標頭,您可以大幅降低 XSS、點擊劫持等攻擊的風險。
建議的實作步驟:
- 先以
Content-Security-Policy-Report-Only測試,收集違規報告 - 逐步放寬政策,確保功能正常運作
- 最終切換為強制模式
Content-Security-Policy - 定期檢視報告,調整政策以因應網站變更
記住:CSP 的核心原則是「預設拒絕,只開放必要來源」。越嚴格的政策,安全性越高,但需要更仔細地規劃每個例外情況。