跨站請求偽造 (CSRF)
1. 定義
跨站請求偽造 (Cross-Site Request Forgery, CSRF) 是一種強制用戶在當前已登入的 Web 應用程式中執行非意願操作的攻擊。
它利用了瀏覽器的 「自動攜帶憑證(Ambient Authority)」 機制:基於目標網域,瀏覽器會自動在跨站請求中包含憑證(如 Session Cookie、Basic Auth 標頭),而不管該請求的觸發源頭。
2. 技術原理
核心漏洞不在於伺服器的身份驗證邏輯,而在於其無法驗證請求的真實意圖。
當用戶登入 bank.com 時,瀏覽器存儲了會話 Cookie session_id=xyz。 如果用戶隨後訪問了惡意網站 evil.com,且該網站包含以下程式碼:
<form action="https://bank.com/transfer" method="POST" id="hack">
<input type="hidden" name="amount" value="1000">
<input type="hidden" name="to" value="attacker">
</form>
<script>document.getElementById('hack').submit();</script>瀏覽器將執行此 POST 請求。關鍵點在於,瀏覽器會自動附加 session_id=xyz Cookie,因為目標地址是 bank.com。伺服器收到有效的 Session Cookie 後處理了轉帳,卻不知道請求實際上源自 evil.com。
3. 攻擊流程 (序列圖)
sequenceDiagram
participant Victim as 用戶瀏覽器
participant Attacker as 惡意網站 (evil.com)
participant Server as 目標伺服器 (bank.com)
Note over Victim, Server: 用戶已登入 (Cookie: session=123)
Victim->>Attacker: 1. 訪問惡意頁面
Attacker-->>Victim: 2. 返回包含自動提交表單的頁面
Note over Victim: 瀏覽器解析 HTML<br/>發現 <form action="bank.com">...
Victim->>Server: 3. 發送 POST /transfer (包含 Cookie: session=123)
Note right of Victim: 瀏覽器自動添加 Cookie<br/>Referer: https://evil.com
Server-->>Server: 4. 驗證 Cookie (通過)<br/>5. 執行轉帳操作
Server-->>Victim: 6. 返回 200 OK (轉帳成功)4. 真實案例:Netflix (2006)
目標: Netflix 「添加到租賃隊列」功能。 漏洞類別: 基於 GET 的 CSRF。
2006 年,研究人員發現 Netflix 的「添加到隊列」操作是通過簡單的 GET 請求完成的: GET http://www.netflix.com/AddToQueue?movieid=70011204
攻擊方式: 攻擊者可以在網頁中植入一個圖片標籤: <img src="http://www.netflix.com/AddToQueue?movieid=70011204" />
當已登入 Netflix 的用戶載入攻擊者的頁面時:
- 瀏覽器嘗試從 Netflix 獲取「圖片」。
- 請求中包含了用戶活躍的 Netflix 認證 Cookie。
- Netflix 伺服器處理了該 GET 請求,並將特定電影添加到了受害者的租賃隊列中。
- 雖然這看起來影響較小,但它證明了可以在未經用戶許可的情況下觸發狀態變更。
影響: 導致了大規模的用戶數據操縱。這迫使 Netflix(以及整個行業)開始嚴格要求對狀態變更操作使用 POST 方法,並實施抗 CSRF 令牌。
5. 深度防禦策略
A. 同步令牌模式 (Synchronizer Token Pattern - 有狀態)
這是最穩固的防禦手段。
生成: 伺服器為用戶會話生成一個加密強度高、唯一且不可預測的隨機令牌(CSRF Token)。
傳輸: 將此令牌作為隱藏欄位嵌入到 HTML 表單中(或作為 AJAX 的特定 HTTP 標頭發送)。
<input type="hidden" name="csrf_token" value="raNDomStr1ng...">驗證: 在執行狀態變更請求(POST、PUT、DELETE)時,伺服器將提交的令牌與會話中存儲的令牌進行比對。
- 如果令牌缺失或不匹配 -> 拒絕請求 (403 Forbidden)。
- 注意: 令牌不得存儲在會被自動發送的 Cookie 中。
B. 雙重提交 Cookie (Double Submit Cookie - 無狀態)
適用於 REST API 等無狀態後端。
- 伺服器在 Cookie 中設置一個隨機值(如
csrf_cookie),同時前端讀取該值並將其放入自定義標頭(如X-CSRF-Token)中發送。 - 伺服器驗證
Cookie.csrf_cookie === Header.X-CSRF-Token。 - 原理: 攻擊者可以觸發發送 Cookie 的請求,但受同源政策 (SOP) 限制,他們無法讀取 Cookie 值來設置自定義標頭。
C. SameSite Cookie 屬性
瀏覽器層面的防禦(深度防禦)。 為會話 Cookie 設置 SameSite 屬性:
SameSite=Strict:跨站請求從不發送 Cookie。(安全性最高,但影響用戶體驗)。SameSite=Lax:僅在安全的頂級導航(如 GET 連結)中發送 Cookie。(良好的平衡點)。
Set-Cookie: session_id=xyz; SameSite=Lax; Secure; HttpOnlyD. 標準標頭驗證 (Standard Headers Verification)
檢查 Origin 和 Referer 標頭。
- 如果存在
Origin,驗證其是否匹配目標網域。 - 注意: 出於隱私原因,這些標頭可能會被瀏覽器(或代理)移除或剝離,因此這應作為一種「深度防禦」的輔助手段,而非主要防禦手段。
