跨站請求偽造(CSRF)入門指南:攻擊原理、實例與防禦方法

更新日期: 2025 年 3 月 4 日

在網路世界中,安全漏洞無處不在,而 跨站請求偽造(CSRF) 正是其中一種常見且危險的攻擊手法。

想像一下:當你登入銀行網站後,不小心點了一個不明連結,結果帳戶裡的錢竟被自動轉走——這就是 CSRF 攻擊的可怕之處。

本文將以 新手友善的視角,完整解析 CSRF 的運作原理、實際攻擊案例,以及開發者該如何防禦。

無論你是剛入門的工程師,還是對資安有興趣的學習者,都能透過這篇文章建立清晰的觀念。


什麼是跨站請求偽造(CSRF)?

CSRF(Cross-Site Request Forgery)是一種利用「用戶已登入的合法身分」發動攻擊的手法。

攻擊者誘導使用者在 不知情的情況下,透過瀏覽器向目標網站發送偽造的請求(例如轉帳、修改密碼),進而執行惡意操作。

以生活情境比喻,假設你有一張「銀行 VIP 會員卡」,只要出示卡片就能辦理業務。

攻擊者偷偷複製了你的卡片(盜用瀏覽器 Cookie),並偽造一張「轉帳申請單」讓你簽名(誘導點擊惡意連結)。

由於銀行只認卡片不認人,攻擊者便成功利用你的身分完成轉帳。


CSRF 攻擊如何運作?

具體流程

1. 用戶登入信任網站,瀏覽器儲存「身分通行證」

  • 當用戶登入 example-bank.com 時,伺服器會發送 Session Cookie 給瀏覽器。
  • Cookie 儲存機制
    • Cookie 由瀏覽器保存在用戶的電腦中(如 Chrome 的 Cookies 資料庫)。
    • 每個 Cookie 嚴格綁定「域名」,例如 example-bank.com 的 Cookie 不會與 evil-site.com 共用。
  • 此時狀態
    用戶如同獲得「銀行 VIP 卡」,後續操作瀏覽器會自動出示此卡驗證身分。

2. 用戶誤入惡意網站,跨分頁的 Cookie 危機

  • 用戶可能在另一個分頁或視窗開啟惡意連結(例如釣魚郵件中的 evil-site.com)。
  • 關鍵行為
    • 瀏覽器會 持續保留所有網站的 Cookie,除非手動清除或 Cookie 過期。
    • 即使切換分頁,example-bank.com 的 Cookie 仍存在瀏覽器中。
      這正是 CSRF 攻擊的核心漏洞!

3. 惡意網站發動「隱形攻擊指令」

  • 攻擊者在 evil-site.com 頁面中暗藏以下程式碼:
  <!-- 偽裝成圖片載入,實際發送轉帳請求 -->
  <img src="https://example-bank.com/transfer?amount=10000&to=ATTACKER" 
       style="display:none">

或使用自動提交的表單:

  <body onload="document.forms[0].submit()">
    <form action="https://example-bank.com/transfer" method="POST">
      <input type="hidden" name="amount" value="10000">
      <input type="hidden" name="to_account" value="ATTACKER_ACCOUNT">
    </form>
  </body>

4. 瀏覽器「自動帶 Cookie」的雙面刃

  • 同源政策(Same-Origin Policy)的盲點
    • 瀏覽器禁止 evil-site.com 讀取 example-bank.com 的 Cookie。
    • 但允許 evil-site.com 發送請求example-bank.com,並自動附加該域名的 Cookie!
      → 請求看似來自已登入用戶,伺服器難以辨別真偽。
  • 攻擊請求的組成
  POST /transfer HTTP/1.1
  Host: example-bank.com
  Cookie: session_id=abc123   # 瀏覽器自動附加!
  Content-Type: application/x-www-form-urlencoded

  amount=10000&to_account=ATTACKER_ACCOUNT

5. 伺服器的致命誤判

  • 伺服器檢查 Cookie 有效 → 認為是合法用戶的操作。
  • 未經驗證直接執行轉帳指令,攻擊成功!

攻擊成功的三大必要條件

條件技術細節範例情境
1. 用戶已登入且 Cookie 有效瀏覽器儲存的 Session Cookie 未過期,且未設定 SameSite 防護屬性用戶登入銀行後未登出,直接瀏覽其他網站
2. 目標網站缺乏 CSRF 防護未使用 CSRF Token、未驗證 Referer、未設定 SameSite Cookie銀行允許純 Cookie 驗證請求,表單未嵌入隨機 Token
3. 惡意請求可構造API 路徑與參數格式可預測(如固定 URL + 簡單參數)銀行使用 POST /transfer?amount=100&to=123 這樣無防護的 API 設計

為什麼 Cookie 機制會成為幫兇?技術深度解析

瀏覽器的「自動化便利」 vs 「安全風險」

  • 設計初衷
    Cookie 是為了讓用戶免於重複登入(例如保持購物車狀態),卻被攻擊者反向利用。
  • 跨站請求的矛盾
  • 瀏覽器的自動化便利性,導致跨站請求「帶著合法身分」闖關成功。

Same-Origin Policy 的不足

  • 僅限制「讀取」跨站資料,卻允許「發送」跨站請求。
    → 攻擊者不需要竊取 Cookie,只需「借用」瀏覽器自動帶上的 Cookie。

實例演練:一個簡單的 CSRF 攻擊

情境設定

假設某銀行提供以下轉帳 API:

POST /transfer
參數:
- amount=1000       # 轉帳金額
- to_account=12345  # 目標帳戶

正常操作流程

用戶在銀行網站手動填寫表單,送出轉帳請求:

<!-- 合法表單 -->
<form action="https://example-bank.com/transfer" method="POST">
  <input type="text" name="amount" value="1000">
  <input type="text" name="to_account" value="12345">
  <button>確認轉帳</button>
</form>

攻擊者構造的惡意頁面

攻擊者建立一個看似無害的頁面,內藏自動提交的表單:

<!-- 惡意頁面 -->
<body onload="document.forms[0].submit()">
  <form action="https://example-bank.com/transfer" method="POST">
    <input type="hidden" name="amount" value="10000">
    <input type="hidden" name="to_account" value="ATTACKER_ACCOUNT">
  </form>
</body>

當已登入銀行的用戶訪問此頁面時,瀏覽器會自動發送轉帳請求,完成攻擊!


如何防禦 CSRF 攻擊?

CSRF Token 驗證

原理:伺服器生成隨機 Token 嵌入表單,提交時驗證是否匹配。

實作範例

<!-- 表單中嵌入 Token -->
<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="RANDOM_STRING">
  <!-- 其他表單欄位 -->
</form>
# 伺服器端驗證
if request.form['csrf_token'] != session['csrf_token']:
    return "Invalid CSRF Token", 403

CSRF Token 的設計核心

CSRF Token 是一種 由伺服器生成的隨機加密字串,其防禦效果依賴以下關鍵特性:

特性技術原理對抗 CSRF 攻擊的作用
隨機性每次表單生成時動態產生(如 UUID v4、加密亂數)攻擊者無法預測或構造有效 Token
與 Session 綁定Token 儲存在伺服器的 Session 中,與當前用戶綁定確保 Token 僅對特定用戶有效
單次使用部分實作中,Token 提交後立即失效(可選策略)防止重放攻擊(Replay Attack)
同源限制Token 只能由合法網站的前端程式碼讀取(遵守同源政策)攻擊者無法從跨站頁面竊取 Token

攻擊者為什麼無法取得 Token?

情境模擬:攻擊者構造惡意表單

假設攻擊者嘗試在 evil-site.com 建立以下表單:

<!-- 惡意頁面 -->
<form action="https://example-bank.com/transfer" method="POST">
  <input type="hidden" name="amount" value="10000">
  <input type="hidden" name="to_account" value="ATTACKER">
  <!-- 攻擊者猜測或偽造 Token -->
  <input type="hidden" name="csrf_token" value="FAKE_TOKEN"> 
</form>
關鍵限制:瀏覽器的同源政策(Same-Origin Policy)
  1. 攻擊者無法讀取合法網站的 Token
    • 即使使用者已登入 example-bank.comevil-site.com 的前端 JavaScript 無法跨域讀取 合法網站的 DOM 內容(包含 Token)。
    • 例:若 Token 嵌入在 <input type="hidden" name="csrf_token" value="abc123">,攻擊者無法透過 JS 取得此值。
  1. Token 不存在於 Cookie 中
    • 伺服器將 Token 儲存在 Session 而非 Cookie,因此瀏覽器 不會自動攜帶 Token 在請求中。

CSRF Token 設計哲學

  1. 隨機性:Token 必須足夠亂數,無法被暴力破解或預測。
  2. 與用戶綁定:透過 Session 確保 Token 專屬於當前用戶。
  3. 同源隔離:依賴瀏覽器同源政策,防止跨站竊取 Token。

「CSRF Token 是伺服器給用戶的一個動態密碼,攻擊者既看不到也猜不到,因此無法偽造合法請求。」

SameSite Cookie 屬性

原理:限制 Cookie 僅在相同網站(Same Site)的請求中傳送。

▶ 設定方法(HTTP Response Header):

Set-Cookie: session_id=abc123; SameSite=Strict
  • Strict:完全禁止跨站請求帶 Cookie(適用敏感操作)
  • Lax:允許部分安全跨站請求(例如導航到目標網站)

驗證請求來源(Referer Header)

原理:檢查 HTTP 請求的 Referer 標頭是否來自合法域名。

▶ 注意:某些瀏覽器可能不發送 Referer,且攻擊者可偽造此值(需搭配其他機制)。

Referer 是什麼?用現實比喻快速理解

什麼是 Referer Header?
  • 技術定義
    HTTP 請求中的 Referer(註:拼寫錯誤是歷史遺留問題,正確應為 Referrer)標頭,代表「這個請求是從哪個網頁連結過來的」。

    例如:當你點擊 news-site.com 上的連結進入 shop.comshop.com 的伺服器會看到:
  GET /product/123 HTTP/1.1
  Host: shop.com
  Referer: https://news-site.com/article/456
  • 比喻理解
    Referer 就像「快遞包裹上的寄件人地址」。
    伺服器(收件人)可以透過地址(Referer)知道包裹(請求)是從哪裡寄來的。

為什麼檢查 Referer 能防禦 CSRF?

正常操作 vs CSRF 攻擊的 Referer 差異
  • 合法操作情境
    用戶在 example-bank.com 的轉帳頁面提交表單 → Referer 是 https://example-bank.com/transfer
  • CSRF 攻擊情境
    用戶在 evil-site.com 被誘導發送轉帳請求 → Referer 是 https://evil-site.com/fake-page

防禦原理

伺服器檢查 Referer 是否來自「自己家的域名」,如果不是就拒絕請求。
例如:

# 伺服器端檢查 Referer 的偽代碼
def process_request(request):
    referer = request.headers.get('Referer')
    if not referer.startswith('https://example-bank.com'):
        return "Request blocked: Invalid Referer", 403
    # 繼續處理請求...

為什麼不能單獨依賴 Referer 檢查?

瀏覽器可能不發送 Referer
  • 隱私設定影響
    某些瀏覽器(如 Firefox 嚴格模式、Brave)或插件(如防追蹤工具)會屏蔽 Referer
  • 從 HTTPS 到 HTTP 的請求
    安全政策規定,若當前頁面是 HTTPS,而請求目標是 HTTP,瀏覽器 不會發送 Referer

案例模擬

用戶在 https://example-bank.com 登入後,從 http://evil-site.com 觸發 CSRF 攻擊:
→ 請求的 Referer 被屏蔽 → 伺服器誤判合法請求!

攻擊者可偽造 Referer(特定條件下)
  • 透過中間攻擊手法
    如果網站存在 開放重定向(Open Redirect)漏洞,攻擊者可構造看似合法的 Referer。
    例如:
  Referer: https://example-bank.com/redirect?url=evil-site.com
  • 利用瀏覽器特性
    某些舊版瀏覽器允許透過 meta 標籤或 JavaScript 修改 Referer,但現代瀏覽器已修復此問題。
跨域子域名的混淆風險
  • 錯誤配置案例
    若伺服器允許所有子域名(如 *.example-bank.com),攻擊者可能註冊 evil.example-bank.com 發動攻擊。
    → Referer 檢查通過,但實際是跨站請求!

實務建議:如何安全使用 Referer 檢查?

僅作為「補充防禦」
  • 絕對不要單獨依賴 Referer,需搭配以下任一機制:
    • CSRF Token
    • SameSite Cookie
    • 自定義請求標頭(如 X-Requested-With
嚴格驗證邏輯
  • 檢查 Referer 的 協議(HTTP/HTTPS)完整域名端口
  • 拒絕空 Referer 或非預期來源。

其他防禦手段

  • 雙重提交 Cookie:將 Token 同時存在 Cookie 和表單,伺服器比對兩者。
  • 自定義 Header:要求 AJAX 請求包含特定 Header(例如 X-Requested-With)。
  • 敏感操作二次驗證:例如要求重新輸入密碼或簡訊驗證碼。

總結與最佳實踐

CSRF 攻擊的關鍵在於 濫用瀏覽器的自動帶 Cookie 機制,而防禦的核心是「確保請求來自合法來源」。

開發者應至少實作以下措施:

  1. 為所有敏感操作啟用 CSRF Token
  2. 為 Session Cookie 設定 SameSite 屬性
  3. 定期更新框架與函式庫(如 Django、Spring Security 已內建 CSRF 防護)。

資安沒有銀彈,唯有持續學習與多層次防護,才能打造更安全的網路環境!

Similar Posts