把 unsafe-inline 從你的 CSP 裡面拿掉? 醒醒吧,你的前端元件會直接罷工!

在網頁資安的攻防戰中,很多工程師在被資安掃描器( 例如 ZAP )洗臉之後,看到報告上寫著大大的「 Medium 風險: style-src 包含 unsafe-inline 」,第一個直覺通常是:「 噢,那我就在 Content-Security-Policy 裡面把 unsafe-inline 拿掉不就得了?」

如果你現在用的是 Vue 3 搭配 Element Plus,而你在拿掉的瞬間,你的網頁基本上就半身不遂了。

  • 短期(建議): 維持 Element Plus,接受 unsafe-inline Medium 風險,專注業務功能。
  • 中期: 若資安掃描壓力大,評估 Naive UI 替換(相同 Vue 生態、學習成本低)。
  • 長期: 新專案直接選 React + shadcn/ui 或 React + Mantine,避免此問題。

兩大資安大哉問: 到底能不能直接拔掉?

我們先把問題拆成兩個層面來看。

1. 在 FastAPI 設定 CSP 跟在 Nginx 設定,有差嗎?

答案是: 完全沒有差別。

瀏覽器是很單純的,它只看最後收到的 HTTP response header。 不管這個資安政策是後端框架 FastAPI 吐出來的,還是前端大門 Nginx 塞給它的,對瀏覽器來說都長得一樣。

目前專案只有在 FastAPI 設定,那就繼續留在那邊就好,不需要特地搬家。

2. 移除 unsafe-inline 之後,Element Plus 還能動嗎?

答案是: 絕對會壞掉,而且壞得很難看。

如果你的 CSP 政策直接移除了 unsafe-inline,下面這些畫面上最亮眼的主角會集體罷工:

  • el-select / el-dropdown: 下拉選單直接迷路,位置飛到九霄雲外或是乾脆隱形。
  • el-tooltip / el-popover: 滑鼠移過去原本該跳出的提示,現在比你的前任還要冷淡,完全沒反應。
  • el-dialog: 彈出視窗直接彈歪,跟你的預期完全對不上。
  • el-table 固定列: 說好要固定的欄位,現在放飛自我跟著一起滾動。

為什麼會這樣? 因為這些元件在運作時,JavaScript 會在幕後瘋狂計算畫面的座標,然後直接把 style="top: 200px; left: 150px;" 這種類型的行內樣式塞進 HTML 標籤裡。

當你把 unsafe-inline 拿掉,瀏覽器就會化身鐵面判官,只要看到這種行內樣式,一律當成非法入侵直接封鎖。 結果就是你的 CSP 報告看起來滿分,但使用者的畫面看起來像一場災難。


那難道無解了嗎? 現代資安的標準解法

好消息是,我們不需要為了資安把整個 Element Plus 換掉( 畢竟換框架是會出人命的 )。 在 CSP Level 3 的現代標準中,資安政策已經被細分得更聰明了。

以前的 style-src 是一刀切,但現在我們可以把「 標籤 」和「 屬性 」分開管理。

你可以試試看這套完美的資安配置:

HTTP

Content-Security-Policy: style-src-elem 'self' https://cdnjs.cloudflare.com; style-src-attr 'unsafe-inline';

這段設定的意思其實就是跟瀏覽器講悄悄話:

  • style-src-elem ‘self’: 只要有人想用 <style> 標籤或外掛惡意 CSS 檔案來劫持網頁,一律給我擋掉! 這招直接封鎖了最危險的 CSS 注入攻擊。
  • style-src-attr ‘unsafe-inline’: 至於 HTML 標籤裡面的 style="..." 屬性,我們就開個特權給它過吧。

改前 vs 改後 戰力分析

這樣改到底差在哪裡? 我們直接看對比:

  • <style> 注入攻擊: 改前是允許的( 超危險 ),改後直接封鎖( 安全 )。
  • 外掛惡意 CSS 檔案: 改前是允許的( 超危險 ),改後直接封鎖( 安全 )。
  • Element Plus 動態定位: 改前正常,改後依然正常運作。
  • 資安掃描器的警告: 改前會跳出黃牌警告,改後警告直接消失。

結論

想兼顧資安跟漂亮的 UI,不需要直接把 unsafe-inline 趕盡殺絕。

透過 style-src-elemstyle-src-attr 的分工合作,你既能把大門關緊防範黑客,又能留個小窗讓 Element Plus 的元件繼續正常跳舞。 這才是現代工程師優雅的解決之道。

結論上來說,改用

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *