內容安全政策(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-srcJavaScript 來源
style-srcCSS 來源
img-src圖片來源
connect-srcfetch/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-toreport-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。