內容安全政策(CSP, Content Security Policy)是一道告訴瀏覽器「這個頁面只准載入/執行哪些來源的資源」的防線,是緩解 XSS 的重要機制。本章不重述攻擊原理,而是聚焦:怎麼用 DevTools 看見 CSP 正在運作、怎麼讀懂它擋了什麼、以及如何用 Report-Only 模式安全地導入。
CSP 長什麼樣子#
CSP 透過回應標頭下發(也可用 <meta>,但標頭較完整):
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data:; frame-ancestors 'none'每個指令限定一類資源的合法來源:
| 指令 | 管的東西 |
|---|---|
default-src | 其他未明確指定者的預設 |
script-src | JavaScript 來源 |
style-src | CSS 來源 |
img-src | 圖片來源 |
connect-src | fetch/XHR/WebSocket 連線目標 |
frame-ancestors | 誰可以把本頁嵌進 iframe(防點擊劫持) |
在 DevTools 看 CSP 違規#
當頁面試圖載入或執行不被政策允許的資源,瀏覽器會擋下它,並在 Console 印出違規訊息:
Refused to execute inline script because it violates the following
Content Security Policy directive: "script-src 'self'". ...觀察步驟:
- Console panel:違規會以紅字出現,訊息會明講「被哪一條指令擋下」。在 Console 篩選框輸入
CSP可快速過濾。 - Network panel:點該頁的主文件 ➡️ Headers,在 Response Headers 找
Content-Security-Policy,確認伺服器實際下發的政策內容(而非你以為的設定)。
看到某個 script、樣式或圖片「沒作用」又沒有網路錯誤時,先去 Console 看是不是被 CSP 擋了。inline 的
<script>與onclick=""在嚴格 CSP 下預設會被擋,這是最常見的「為什麼我的程式碼沒跑」原因之一。
Report-Only:先觀察,不阻擋#
直接上線一套嚴格 CSP,很可能誤擋正常資源、把網站弄壞。正確的導入方式是先用 Report-Only 模式:政策照常評估、違規照常回報,但不真的阻擋。
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint- 瀏覽器會在 Console 印出「假如啟用會被擋」的項目,但資源仍正常載入。
- 搭配
report-to/report-uri,違規會以 JSON 自動回報到你指定的端點,方便長期蒐集。
導入流程:先掛
Report-Only➡️ 在 Console 與回報端點觀察一段時間 ➡️ 逐一把誤報的合法來源加進白名單 ➡️ 確認乾淨後,才把標頭換成正式的Content-Security-Policy開始真正阻擋。
為什麼要避免 ‘unsafe-inline’#
很多人為了讓現有的 inline script/style 不被擋,直接加上 'unsafe-inline'——但這等於把 CSP 對 XSS 的防護打了個大洞,因為注入的 inline 腳本也會被放行。
小結#
- CSP 透過回應標頭限定各類資源的合法來源,是緩解 XSS 的關鍵防線。
- Console 看違規訊息(會講明被哪條指令擋)、Network ➡️ Headers 看實際下發的政策。
- 用
Content-Security-Policy-Report-Only先觀察、收集違規,再切換成正式阻擋。 - 別用
'unsafe-inline'圖方便,改用 nonce/hash。