
所有 Web 攻擊都可以歸結為一個模式:攻擊者的輸入 → 系統沒正確處理 → 非預期行為。差別只在「非預期的行為」發生在哪裡。本篇講三個最常見的:XSS、SQL Injection、CSRF。SSRF、CORS 和安全 Headers 放在下一篇。
先講結論
XSS 是你的網站幫攻擊者跑了 JavaScript,SQLi 是你的查詢被攻擊者改寫了,CSRF 是攻擊者借用了你的登入狀態。三個的防禦核心都一樣:不要信任使用者的輸入。
XSS——你的網站替攻擊者執行了 JavaScript
Cross-Site Scripting 的本質:攻擊者的文字被你的網頁當成 HTML/JS 來解析。
三種口味:Stored XSS(惡意內容存進 DB,所有人看到都中招,最危險)、Reflected XSS(惡意內容在 URL 參數裡,點連結才中招)、DOM-based XSS(前端 JS 直接把使用者輸入塞進 DOM)。
攻擊者拿到 XSS 能幹嘛?偷 session cookie 冒充使用者、修改頁面內容做釣魚、記錄鍵盤輸入偷密碼。夠嚇人了吧?
防禦的核心:永遠不要信任使用者的輸入。
✗ element.innerHTML = userInput
✓ element.textContent = userInput
✗ <div dangerouslySetInnerHTML={{__html: userInput}} />
✓ 用框架的自動 escape(React 預設就會 escape)
再加一層保險——CSP(Content Security Policy):
Content-Security-Policy: default-src 'self'; script-src 'self'它告訴瀏覽器「只允許執行來自這些來源的 script」。即使攻擊者成功注入了 script 標籤,瀏覽器也不會執行。這大概是最強的 XSS 防禦了。
順帶一提,你的專案裡搜一下 innerHTML 和 dangerouslySetInnerHTML——每一個都是潛在的 XSS 點。
SQL Injection——你的查詢被攻擊者改寫了
使用者輸入被當成 SQL 語法的一部分執行。經典到不能再經典,但 2026 年了還是到處都有。
-- 你寫的
SELECT * FROM users WHERE name = '{userInput}'
-- 使用者輸入: ' OR '1'='1
-- 實際執行的
SELECT * FROM users WHERE name = '' OR '1'='1'
-- 恭喜,回傳所有使用者更刺激的版本:
-- 使用者輸入: '; DROP TABLE users; --
-- 整張表沒了,不客氣防禦:只有一個正確答案——Parameterized Query。
// ✗ 字串拼接——永遠不要這樣做
db.query(`SELECT * FROM users WHERE id = ${userId}`)
// ✓ Parameterized Query
db.query('SELECT * FROM users WHERE id = $1', [userId])「但我用 ORM 啊?」——ORM 內部用 parameterized query,所以通常安全。但你用 raw query 的時候呢?去搜搜看你的 codebase 裡有沒有 template literal 拼接 SQL 的地方。
額外防禦層:DB 帳號只給 SELECT 不給 DROP、錯誤訊息別透露 SQL 結構、WAF 過濾常見 injection pattern。但這些都是保險,parameterized query 才是本體。
CSRF——攻擊者借用了你的登入狀態
Cross-Site Request Forgery 的劇本:你登入了銀行網站(cookie 還在),打開了一封釣魚信裡的連結,惡意頁面裡藏了一個 <img src="https://bank.com/transfer?to=attacker&amount=10000" />,瀏覽器自動帶上你的 cookie,銀行以為是你在操作。
錢就這樣轉走了。你什麼都沒點。
防禦有三招:
- CSRF Token——每個表單帶一個隨機 token,server 端驗證。攻擊者不知道 token 值,偽造的 request 會被擋掉
- SameSite Cookie——
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly。告訴瀏覽器跨站請求別帶 cookie - 檢查 Origin/Referer header——確認 request 來自你的網站(輔助手段)
如果你用 SPA + JWT,天生不太受 CSRF 影響,因為 token 不會被瀏覽器自動帶上。但用 cookie-based session 的話?CSRF 防禦是必須的,沒有討論空間。
你的系統信任了不該信任的東西,攻擊者就是那個利用這份信任的人。下一篇來看 SSRF、CORS 和安全 Headers。
延伸閱讀
- Web 安全實務(下):SSRF、CORS 與安全 Headers — 本篇的續集
- 資安基礎概念 — CIA Triad 和威脅模型
- 紅隊與藍隊 — 用攻防思維看這些漏洞
- 安全開發生命週期 — 在開發流程中防止這些問題