Web 安全實戰:
XSS、CSRF、CSP 防禦
跨站腳本攻擊、跨站請求偽造、內容安全策略 — OWASP Top 10 前端工程師必懂的攻防
Section 1:XSS(Cross-Site Scripting)跨站腳本攻擊
XSS 是 OWASP Top 10 長年榜上的攻擊類型。攻擊者將惡意 JavaScript 注入到網頁中,當其他用戶查看這個頁面時,惡意腳本就在他們的瀏覽器中執行,可以竊取 Cookie、劫持 Session、偽造操作。XSS 分為三種類型:
Reflected XSS
風險 中反射型:攻擊程式碼夾帶在 URL 中,點擊連結觸發
Stored XSS
風險 高儲存型:惡意碼存入資料庫,每個看此頁的用戶都中招
DOM-based XSS
風險 中DOM 型:前端 JS 直接操作惡意資料到 DOM 中
Reflected XSS 攻擊示例
Stored XSS 攻擊示例(最危險)
React 前端防禦
後端 Node.js 防禦
Section 2:CSRF(Cross-Site Request Forgery)跨站請求偽造
CSRF 攻擊利用「瀏覽器自動帶 Cookie」的特性。只要用戶已登入某網站,攻擊者只需讓用戶的瀏覽器發出請求,就可以用用戶的身份執行操作,不需要竊取 Cookie。
攻擊原理(銀行轉帳示例)
防禦方式 1:CSRF Token(最常用)
防禦方式 2:SameSite Cookie(現代首選)
防禦方式 3:Origin / Referer 標頭檢查
Section 3:CSP(Content Security Policy)內容安全策略
CSP 是 XSS 的「第二道防線」。即使 XSS 注入成功,透過 HTTP Header 告訴瀏覽器「只允許執行來自特定來源的資源」,惡意腳本依然無法執行或連線到攻擊者的伺服器。
CSP 的核心思路
傳統安全假設:「過濾掉壞的輸入就安全了」。CSP 的思路:「就算壞輸入進來了,瀏覽器也不執行不在白名單的程式碼」。這是縱深防禦(Defense in Depth)的體現。
Express 中設定 CSP
Next.js 設定 CSP(next.config.js)
CSP 的常見困境:inline script
許多前端框架(包括 Next.js)需要 inline script 來注入初始狀態。解決方案是使用 nonce:每次請求隨機生成一個 token,只允許帶有這個 token 的 inline script 執行。Next.js 14+ 內建 CSP nonce 支援。
Section 4:SQL Injection — 後端的基本功
SQL Injection 是最古老、最危險的攻擊之一。攻擊者透過在輸入中插入 SQL 語法,改變查詢的語義,可以讀取任意資料、刪除資料庫、甚至取得伺服器控制權。防禦方法很簡單卻也最重要:永遠使用參數化查詢。
攻擊示例
正確防禦方式
永遠不要做的事
- • 用 string concatenation 拼接 SQL
- • 用 eval() 執行動態查詢
- • 相信前端傳來的欄位名稱
- • 使用 root 帳號連接資料庫
最佳實踐清單
- • 永遠使用參數化查詢或 ORM
- • 資料庫帳號使用最小權限原則
- • 敏感欄位(如 password)用 bcrypt 加密
- • 定期備份並測試還原
Section 5:其他常見安全問題速查
Web 安全的攻擊面遠不止 XSS 和 CSRF。以下是 OWASP Top 10 涵蓋的其他常見安全問題與對應防禦策略。
| 攻擊類型 | 說明 | 防禦方式 |
|---|---|---|
| Clickjacking | 將你的網站透明地疊在惡意頁面上,誘騙用戶點擊 | X-Frame-Options: DENY 或 frame-ancestors 'none' |
| Man-in-the-Middle | 攔截網路通訊,竊取或竄改傳輸中的資料 | HTTPS + HSTS (Strict-Transport-Security) |
| Sensitive Data Exposure | 密碼、Token 出現在 URL、Log、錯誤訊息中 | 用 POST body 傳遞敏感資料,不記錄敏感 Log |
| Broken Authentication | 弱密碼、明文存密碼、Session 未過期、暴力破解 | bcrypt 存密碼、JWT 短效期、Rate Limit 登入 |
| Insecure Deserialization | 惡意構造的序列化物件,執行任意程式碼 | 驗證反序列化資料型別,不執行用戶提供的程式碼 |
| Open Redirect | 利用網站的重導向功能,把用戶導向釣魚網站 | 只允許重導向到白名單 URL,不信任 URL 參數 |
| Path Traversal | 用 ../../ 存取超出允許範圍的檔案 | 驗證檔案路徑,使用 path.resolve 並檢查前綴 |
| Mass Assignment | 攻擊者在請求中加入 isAdmin: true 等未預期欄位 | 使用白名單明確指定允許更新的欄位 |
Open Redirect 的正確防禦
Section 6:安全 Headers 完整清單
HTTP 安全標頭(Security Headers)是告訴瀏覽器如何處理你的網站的指令,可以在不修改任何業務程式碼的情況下大幅提升安全性。Express 的 helmet 中間件一次設定所有常用安全標頭。
使用 Helmet(最快的方式)
認識每個安全 Header
Content-Security-Policy必須default-src 'self'; script-src 'self'最重要的安全標頭,控制哪些資源可以被載入和執行。XSS 的最後防線。
Strict-Transport-Security重要max-age=31536000; includeSubDomains強制瀏覽器一律使用 HTTPS 訪問此網站,防止 Man-in-the-Middle。
X-Content-Type-Options建議nosniff防止瀏覽器嗅探 MIME type,避免把文字檔案當腳本執行。
X-Frame-Options建議DENY防止你的網頁被嵌入 iframe(Clickjacking 防禦),被 CSP frame-ancestors 取代。
Referrer-Policy選用strict-origin-when-cross-origin控制 Referer 標頭揭露的資訊,防止敏感 URL 洩露給第三方。
Permissions-Policy選用camera=(), microphone=(), geolocation=()禁止頁面使用特定瀏覽器 API,例如攝影機、麥克風、地理位置。
安全是持續的過程,不是一次性設定
只要加上 helmet(),你的 Express 應用立刻達到業界標準安全配置。但安全不是一次設定就永遠安全 — 需要持續關注 npm audit 的安全警告、依賴套件的更新、以及業務邏輯中新增的漏洞。定期進行安全審計(Security Audit)和滲透測試,是成熟工程團隊的標準實踐。