先給結論:這四件事的「框架相關性」差很多,前兩個有差,後兩個基本沒差。
| 項目 | 框架有沒有差 | 原因 |
|---|---|---|
| XSS(Cross-Site Scripting,跨站腳本攻擊) | 差很多 | 它發生在「模板渲染」這層,而模板引擎就是框架的核心 |
| CSRF(Cross-Site Request Forgery,跨站請求偽造) | 差在「有沒有內建」 | 需要伺服器發 token,所以差異主要在後端框架 |
| 權限控管 | 幾乎沒差 | 這是應用邏輯,框架只給你一個掛載點 |
| 稽核紀錄(Audit Log) | 完全沒差 | 框架不管這件事 |
三個框架都預設會轉義插入的文字,但兩件事不同:逃生門的名字,以及有沒有做淨化。
| 框架 | 預設行為 | 逃生門(繞過保護的寫法) | 名字有警告嗎 |
|---|---|---|---|
| React | {} 內的值自動轉義 |
dangerouslySetInnerHTML |
✅ 名字直接罵你 |
| Vue | {{ }} 自動轉義 |
v-html |
❌ 完全看不出危險 |
| Angular | 自動轉義+主動淨化 | bypassSecurityTrustHtml |
✅ 有警告 |
| Svelte | 自動轉義 | {@html ...} |
❌ 沒警告 |
Angular 是四個裡最嚴格的,因為它多做了一層別人沒做的事:
轉義(escape):把 < 變成 <,內容原樣顯示但瀏覽器不執行。React、Vue、Svelte 做的是這個。
淨化(sanitize):真的去解析那段 HTML,把危險的部分挑掉(拿掉 <script>、拿掉 onerror=),保留安全的標籤。Angular 的 DomSanitizer 做的是這個。
差別在於:如果你要讓使用者貼「有格式的文字」(例如富文本編輯器的內容),React 和 Vue 只給你「全轉義」或「全放行」兩個極端,中間那層要自己裝 DOMPurify;Angular 內建就有。
(順帶一提,你的 next-one-main 的 package.json 裡有 isomorphic-dompurify,那就是在補這一層。)
a. URL 屬性
<a href={userInput}>點我</a>
白話講:使用者如果輸入 javascript:alert(1),這行就變成可執行的連結。React 只會在 console 印警告,不會阻止,Vue 和 Svelte 更是完全不管。自動轉義只管「文字內容」,不管「屬性值的語意」。
b. CSS 注入與 <style> 標籤
框架的轉義機制對 CSS 完全沒有概念。
c. 沒有經過框架的注入
這一點跟你被駭那件事直接相關。 你那個 <script src="data:text/javascript;base64,..."> 是在伺服器回應 HTML 的當下被插進 <head> 的——它根本沒有經過 React 的渲染流程,所以 React 的自動轉義從頭到尾沒有機會介入。
框架的 XSS 防護只能保護「從框架流進去的資料」。 一旦攻擊者能改 HTTP 回應本身,換哪個框架都一樣。
| 框架 | 有沒有內建 CSRF 防護 |
|---|---|
| Next.js | 一般 API Route 沒有;Server Actions 有 Origin/Host 比對 |
| Nuxt | 沒有,要裝 nuxt-security |
| Angular | 有(HttpClientXsrfModule,但要後端配合放 cookie) |
| Rails/Django/Laravel | 有,而且預設開啟 |
關鍵認知:CSRF 主要是後端框架的責任,不是前端框架的。
因為 CSRF token 必須由伺服器產生、由伺服器驗證,前端只是負責把它帶上。React、Vue 是 UI 層,它們沒有「伺服器」可以發 token。
Angular 之所以有,是因為它是全功能框架,內建了 HTTP client,所以順便把「自動從 cookie 讀 token 塞進 header」這件事包進去。
而且現在主流解法已經跟框架無關了——SameSite cookie 屬性:
Set-Cookie: session=xxx; SameSite=Lax; Secure; HttpOnly
白話講:這行告訴瀏覽器「從別的網站發過來的請求,不要帶這個 cookie」。這是瀏覽器層的防護,換什麼框架都一樣有效,也是為什麼新專案對傳統 CSRF token 的依賴降低了。
各框架提供的「掛載點」名字不同,但做的事一樣:
Next.js → middleware.js
Angular → Route Guards(路由守衛)
Vue Router → navigation guards(導航守衛)
React Router → loader 或自己包一層 <RequireAuth>
但這裡有一句比框架比較重要一百倍的話:
前端的權限控管只是 UI,不是安全。
任何前端的守衛都可以被繞過——打開 DevTools 改變數、直接用 curl 打你的 API、把 JS 改掉再執行。前端的權限判斷只是「不要讓使用者看到他不該看的按鈕」,真正的守門員必須在後端。
這一點正好對上你專案的問題:/api/website-content 這個端點對全世界公開回傳 130 KB 的內部資訊。前端有沒有藏起來完全不重要,因為攻擊者是直接打那個網址。
所以權限控管要問的不是「我的框架怎麼做」,而是**「每一個 API 端點都有自己驗過身分嗎」**。
這個沒有框架差異,因為它根本不在框架的職責範圍。稽核紀錄屬於三個地方:
後端應用層:誰在什麼時間對什麼資源做了什麼操作,寫進 audit table
資料庫層:觸發器(trigger)、或 CDC(Change Data Capture,變更資料擷取)
基礎設施層:APM(Application Performance Monitoring)、log 聚合服務
前端框架連「使用者是誰」都只是暫存在記憶體裡,沒有資格當稽核來源——因為前端送上來的任何東西都可以被偽造。
框架能幫你的,只有「資料從框架流進畫面」那一段(XSS)。
CSRF 是後端的事,權限控管是 API 的事,稽核是資料庫和基礎設施的事。
所以「換一個更安全的框架」這個想法,只在 XSS 這一項上有意義,而且效果有限。