
接續上一篇的 XSS、SQLi、CSRF,這篇來看三個容易被忽略但殺傷力不小的東西:SSRF、CORS 的真面目、以及你的 production 網站可能缺少的安全 Headers。
先講結論
SSRF 是你的 server 幫攻擊者存取了內部資源,CORS 不是安全機制而是存取控制(搞混了你會裸奔),security headers 是花 5 分鐘就能設好的免費防禦層。
SSRF——你的 Server 變成攻擊者的跳板
Server-Side Request Forgery 的劇本:攻擊者讓你的 server 去請求他指定的 URL。問題是,你的 server 在內網裡,能碰到很多外面碰不到的東西。
攻擊者: "請幫我抓這個 URL 的內容"
URL: http://169.254.169.254/latest/meta-data/iam/security-credentials/
↑
AWS metadata API!
可以拿到 IAM credentials
哪些功能最容易中招?「預覽 URL」功能、圖片 URL 下載、Webhook 設定、PDF 生成(如果接受外部 URL)。基本上任何接受使用者提供的 URL 然後你的 server 去 fetch 的功能,都是 SSRF 的溫床。
防禦:
// ✗ 直接拿使用者給的 URL 去 fetch
const response = await fetch(userProvidedUrl)
// ✓ 白名單 + URL 驗證
function isAllowedUrl(url) {
const parsed = new URL(url)
if (isInternalIP(parsed.hostname)) return false // 禁止內部 IP
if (!['http:', 'https:'].includes(parsed.protocol)) return false
if (!ALLOWED_DOMAINS.includes(parsed.hostname)) return false
return true
}你的 API 有接受 URL 作為參數的 endpoint 嗎?那就是潛在的 SSRF。
CORS——它不是你以為的安全機制
最常見的誤解:「設了 CORS 就安全了。」
不,CORS 的本質是:告訴瀏覽器「哪些外部網站可以讀取我的 API 回應」。注意關鍵字——瀏覽器。Server-to-server 的請求完全不受 CORS 影響。CSRF 也不是靠 CORS 防的(preflight 只對某些 request 類型有效)。
最危險的設定:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
# ↑ 同時開這兩個等於沒設正確的做法:
// 只允許你的前端域名
const allowedOrigins = ['https://yourdomain.com']
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
},
credentials: true
}))CORS 是存取控制,不是安全機制。搞混這兩件事,你以為自己有防禦,其實在裸奔。
安全 Headers——5 分鐘設好的免費防禦
這些 HTTP headers 應該在你的所有 production 網站上設定,但我敢打賭你的網站少了至少兩個:
Content-Security-Policy: default-src 'self'——限制可執行的資源來源,XSS 的最後一道防線Strict-Transport-Security: max-age=31536000; includeSubDomains——強制 HTTPS,不給降級攻擊機會X-Content-Type-Options: nosniff——防止 MIME type sniffingX-Frame-Options: DENY——防止被 iframe 嵌入(clickjacking 防禦)Referrer-Policy: strict-origin-when-cross-origin——控制 Referer header 洩漏多少資訊
不信的話,去 securityheaders.com 掃一下你的網站。看到那個 F 的時候別太驚訝。
設定這些 headers 大概花你 5 分鐘。不設的話,你就是在跟攻擊者說「我這邊防禦很鬆,歡迎光臨」。反正你本來就很歡迎大家來嘛。
Web 安全的本質就一句話:不要信任任何來自外部的東西。聽起來很偏執?在安全領域,偏執才是正確的態度。
延伸閱讀
- Web 安全實務(上):XSS、SQL Injection、CSRF — 本篇的前篇
- 資安基礎概念 — CIA Triad 和威脅模型
- 安全開發生命週期 — 在開發流程中防止這些問題
- API 設計與認證機制 — 認證機制的安全設計