CSRF 跨站請求偽造完全指南

深入 CSRF:攻擊原理、與 XSS/CORS 的差異、SameSite cookie、CSRF token、Origin 檢查等防護

屬於 OWASP Top 10 範疇;常與 XSS 及 CORS 混淆,本篇特別釐清。


目錄


什麼是 CSRF?

CSRF(Cross-Site Request Forgery,跨站請求偽造) 是誘使已登入的受害者,在不知情下對目標網站送出他本意之外的請求。攻擊者「借用」受害者已通過認證的身分去執行操作。

受害者已登入 bank.com(瀏覽器有 bank.com 的 cookie)
   → 受害者被誘導開啟攻擊者的網頁
   → 該網頁偷偷對 bank.com 送出「轉帳」請求
   → 瀏覽器自動帶上 bank.com 的 cookie → 銀行以為是受害者本人操作

關鍵:攻擊者看不到回應,但能讓有副作用的操作發生(轉帳、改密碼、刪資料)。


為什麼 CSRF 可行

根因:瀏覽器在跨站請求時,會自動帶上目標網站的 cookie

對 bank.com 的任何請求(不管從哪個網頁發起)
   → 瀏覽器自動附上 bank.com 的 session cookie
   → 伺服器只看 cookie 判斷身分 → 無法分辨是本人還是被偽造的請求

只要網站只靠 cookie 判斷身分、且不驗證請求來源,就可能被 CSRF。


攻擊範例

用表單自動送出(POST)

<!-- 攻擊者的網頁 -->
<form action="https://bank.com/transfer" method="POST" id="f">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById("f").submit();</script>
<!-- 受害者一開這頁,就自動對 bank.com 送出轉帳,並自動帶上其 cookie -->

用 GET(更簡單,若該操作竟用 GET)

<!-- 若轉帳能用 GET 觸發,一張圖就夠 -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">

這也是「有副作用的操作絕不能用 GET」的原因之一。


CSRF vs XSS

兩者常被搞混,但機制完全不同:

面向 CSRF XSS
本質 偽造請求(借用既有登入) 注入腳本(在受害者瀏覽器執行)
攻擊者能讀回應嗎 不能(被同源政策擋) 能(腳本在受害者頁面內)
依賴 瀏覽器自動帶 cookie 頁面有可注入點
危害 以受害者身分執行有副作用操作 幾乎全能(偷 token、冒名、側錄)
主防護 SameSite / CSRF token / 驗來源 輸出編碼 / CSP / 淨化

一句話:CSRF 是「借你的手做事」,XSS 是「在你家裡植入間諜」。 XSS 通常更嚴重(且 XSS 可繞過多數 CSRF 防護)。


現代最主要、最省力的防線:給 cookie 設 SameSite,限制它在跨站請求時是否送出。

Set-Cookie: session=abc; SameSite=Lax; Secure; HttpOnly
行為
Strict 跨站請求完全不送 cookie(最嚴,但從外站連回來會像未登入)
Lax(多數瀏覽器預設) 跨站的安全導覽(GET 連結)會送,但跨站 POST/表單不送 → 擋掉多數 CSRF
None 一律送(需配 Secure)——跨站情境才用
  • Lax 預設已能擋掉大部分 CSRF(跨站 POST 不帶 cookie)
  • Lax 對「跨站 GET」仍送 cookie → 所以有副作用操作別用 GET

防護二:CSRF Token

傳統且可靠的防線:Synchronizer Token Pattern

伺服器產生隨機 CSRF token → 嵌進表單(隱藏欄位)/ 回給前端
提交時必須帶上這個 token → 伺服器驗證
<form method="POST" action="/transfer">
  <input type="hidden" name="csrf_token" value="隨機且綁定 session 的值">
  ...
</form>
  • 攻擊者的網頁拿不到這個 token(同源政策擋住它讀取受害者頁面內容)→ 偽造的請求缺 token → 被拒
  • 變體 Double-Submit Cookie:token 同時放 cookie 與請求參數,伺服器比對兩者是否一致(不需 server 端儲存)

防護三:檢查 Origin / Referer

伺服器檢查請求的 OriginReferer 標頭是否來自自己的網站:

若 Origin 不是 https://bank.com → 拒絕
  • 瀏覽器會在跨站請求帶上 Origin,攻擊者無法偽造(JS 改不了這些受保護標頭)
  • 常作為 SameSite / token 之外的額外驗證

防護四:避免用 GET 做有副作用的操作

安全的 HTTP 方法語意本身就是一道防線:

  • GET 應該是安全的(純讀取、無副作用)——見 REST 的安全性與冪等性
  • 把轉帳、刪除等放在 POST/PUT/DELETE,就避免「一張 <img> 或一個連結」觸發
  • 配合 SameSite=Lax(跨站 POST 不帶 cookie),效果更好

CSRF 與 CORS 的關係(常見混淆)

這是最多人搞錯的地方:CORS 不能防 CSRF,甚至方向相反。

CORS:控制「JavaScript 能不能讀取跨來源回應」
CSRF:偽造請求讓副作用發生(攻擊者根本不需要讀回應)
  • CSRF 攻擊不需要讀回應——它只要讓「轉帳發生」即可,所以 CORS 擋不到它
  • CORS 是放寬跨來源「讀取」的機制,不是「防護」機制;設錯 CORS 反而擴大風險
  • 防 CSRF 要靠 SameSite / CSRF token / 驗 Origin,不是靠 CORS

詳細的 CORS 機制見 CORS 篇(同分類)。記住:CORS 管「能不能讀」,CSRF 管「請求被不被偽造」,是兩回事。


常見問題

問題 1:CSRF 和 XSS 差在哪?

CSRF 偽造請求、借用受害者既有登入做有副作用操作,攻擊者讀不到回應;XSS 注入腳本在受害者瀏覽器執行,幾乎全能。XSS 通常更嚴重,且能繞過 CSRF 防護。

問題 2:有了 SameSite 還需要 CSRF token 嗎?

SameSite=Lax 已擋多數 CSRF,但仍建議縱深防禦:對重要操作加 CSRF token 或驗 Origin,以防瀏覽器差異、SameSite=None 的場景、或子網域問題。

問題 3:CORS 可以防 CSRF 嗎?

不能。CORS 管的是「JS 能否讀取跨來源回應」,而 CSRF 不需要讀回應、只要讓請求發生。防 CSRF 要用 SameSite / token / Origin 檢查。

問題 4:純 token(放 Authorization 標頭、不靠 cookie)還會 CSRF 嗎?

若身分驗證不靠瀏覽器自動帶的 cookie,而是 JS 主動把 token 放進 Authorization 標頭,攻擊者的網頁無法替你加這個標頭 → 天生較不受 CSRF 影響。但這類 token 若存 localStorage,又更暴露於 XSS——是一個取捨。

問題 5:為什麼有副作用的操作不能用 GET?

因為 GET 太容易被觸發(<img>、連結、預載),且 SameSite=Lax 對跨站 GET 仍會帶 cookie。把副作用放 POST/PUT/DELETE 能避免這些被動觸發。


總結

核心要點

  • CSRF:誘使已登入受害者送出非本意請求,借用其登入身分執行有副作用操作
  • 根因:瀏覽器跨站請求會自動帶 cookie,伺服器只看 cookie 就無法分辨真偽
  • 攻擊者讀不到回應,所以 CORS 擋不了 CSRF(兩者是不同問題)
  • 主防護:SameSite=Lax/Strict cookie(現代主力)+ CSRF token + 驗 Origin/Referer
  • 有副作用操作別用 GET
  • 與 XSS 區別:CSRF 偽造請求、XSS 注入腳本;XSS 通常更嚴重且能繞過 CSRF 防護

快速參考

防護 作用
SameSite=Lax/Strict 跨站請求不帶 cookie(主力)
CSRF token 攻擊者拿不到 → 偽造請求缺 token 被拒
驗 Origin/Referer 確認請求來自本站
副作用用 POST 避免被 <img>/連結被動觸發
⚠️ CORS 不能防 CSRF(管的是「能否讀回應」)

建立日期:2026-06-18

🔗相關文章