不用密碼也能動到資料?CSRF 是什麼以及它如何攻擊你的網站

在網站開發的世界裡,只要是需要「登入後才能操作」的系統,工程師一定會遇到兩類問題:

🔐 密碼洩漏,以及登入後的權限被濫用。

大多數人都以為資安風險只跟密碼有關,但真正讓網站最容易受傷的,往往不是密碼,而是使用者「正在登入中」的這件事。

這也正是 CSRF(跨站請求偽造)可怕的地方。
攻擊者不需要破解你的後台、不需要猜你的密碼、不需要鑽入你的 server,只要讓你在登入狀態下「點了一個連結」、或「載入了一個外部資源」,
你的瀏覽器就會替攻擊者發出一個看起來完全合法的請求。

簡單來說:
攻擊不發生在駭客電腦,而是發生在你的瀏覽器。
這讓使用者以為「我什麼都沒做」,但資料卻已經被修改、刪除,甚至被轉出。

CSRF 並不是一個冷知識,而是每一位工程師、網站管理者、甚至品牌經營者,都應該理解的基本資安概念。因為它利用的不是漏洞,而是系統本身對使用者「已登入狀態」的信任。

什麼是 CSRF?從技術原理理解它如何被利用

如果要用一句話解釋 CSRF,那就是:

「攻擊者利用你已經登入的狀態,讓你的瀏覽器幫他做事。」

一旦這個指令被網站接受,攻擊者就有機會完成:

  • 修改帳戶資訊
  • 更改 Email 或密碼
  • 在後台刪除資料
  • 發出訂單
  • 在某些系統中甚至可以進行金錢操作

CSRF 是怎麼發生的?從一次普通的操作看清攻擊流程

要理解 CSRF,可以從一個非常日常的情境開始。
想像你剛登入網站後台,瀏覽器此時已經保存了代表你身分的 Cookie。只要這段時間內你還保持登入,瀏覽器就會在每一次請求中自動帶上這份資料,讓網站知道「這是你」。

問題也就出現在這裡。

如果此時你的瀏覽器同時開啟了另一個看似無害的網頁,而那個頁面偷偷放了一段請求(可能是隱藏表單、可能是一張偽造的圖片網址),瀏覽器在載入它時會自然地將後台的 Cookie 一起送出。
網站收到後,看見 Cookie 合法、格式正常,就會誤以為這是你本人發出的操作。

在許多系統中,這樣的請求可能代表:

  • 修改帳號設定
  • 刪除某篇內容
  • 提交一筆交易
  • 在後台執行某個敏感指令

整個過程沒有密碼破解、沒有入侵伺服器,也沒有暴力攻擊。
瀏覽器只是「照著它的規則在做事」,而攻擊者做的事情,就是讓你的瀏覽器替他按了一個你根本沒有打算按的按鈕。

CSRF 的本質就在這裡:

攻擊者不直接攻擊網站,而是攻擊「你與網站之間的信任」。

CSRF 常見的真實案例:你可能以為是 Bug,但其實是被利用了

CSRF 的攻擊方式看似抽象,但真正可怕的是,它往往會以非常「正常」的系統行為呈現。
很多工程師第一次遇到時,甚至會誤以為是使用者操作錯誤、後台 Bug、或前端行為異常。

以下是最常被提到、也最容易在實務開發中發生的幾個情境:

1. 後台資料莫名被修改

有些客戶會反應:「我沒有按任何東西,為什麼後台某個欄位突然變了?」

如果該操作剛好是後台提供的 GET 或 POST API 又沒有額外驗證機制,攻擊者只要構造一個請求、讓使用者在登入期間載入:

則資料會以使用者身分被修改
Log 也會記錄「這位使用者自己做的」

這種情況在舊系統、或後台 API 只做 session 驗證的專案中非常常見。

2. Email 或密碼被改掉,但系統顯示「使用者本人操作」

例如會員中心允許使用者透過簡單的 POST 請求更改 Email 或密碼。
攻擊者只需要放置一個隱藏表單:

<form action="https://example.com/user/update-email" method="POST">
  <input type="hidden" name="email" value="attacker@example.com">
</form>
<script>document.forms[0].submit()</script>
  

只要使用者在登入狀態下開啟這個頁面,瀏覽器就會自動附上 Cookie。
結果是:

  • Email 變成攻擊者的
  • 密碼重設通知會寄到攻擊者那裡
  • 使用者直接被鎖在帳號外面

很多人直到這個階段才意識到 CSRF 的威力。

3. 電商網站中「意外送出訂單」

如果購物車的送單 API 沒做防護、僅依靠 Cookie 驗證身分,攻擊者可以:

  • 自行填好購物車內容
  • 讓使用者載入一段 JS 或一個連結
  • 使用者瀏覽器就會「代替他送出訂單」

多半會被誤認為使用者自己誤按,但其實是 CSRF 造成的。

4. 舊版後台的刪除按鈕未受保護

很多舊後台都有類似 URL:

https://example.com/admin/delete?id=14
  

如果這個 URL 只需要 Cookie 就能執行刪除,那攻擊者只需要:

<img src="https://example.com/admin/delete?id=14">
  

當一張看似無害的圖片被載入,刪除請求就已經發出了。

這是 CSRF 最典型、也是歷史最悠久的攻擊方式之一。

5. 在公司內部系統中,意外變更關鍵數據

許多企業內網使用固定登入、不登出習慣。
攻擊者只要在公司 Slack、Line、或 Email 中放入連結:

  • 點開
  • 請求送出
  • Cookie 被附上
  • 資料在後台被改寫

而因為操作來自「公司內部已登入 IP」,往往更難被察覺。

後端工程師如何防範 CSRF?不同架構、不同行為的最佳做法

在所有 CSRF 防禦手法裡,後端永遠是最關鍵的一層,因為只有後端能真正判斷「這個請求是不是使用者本人授意」。
而根據你採用的技術架構不同,防禦方式也會有些差異。

以下整理我整理我平常會碰到的兩種情況:
Laravel 等主流框架,以及 純 PHP 沒有框架的環境

兩者的核心想法相同,但實作方式不太一樣。

一、如果你用的是 Laravel:CSRF Token 是框架預設的安全機制

Laravel 預設就啟用了 CSRF 防護,只要專案有 Session,就會自動為每位使用者產生一組 token,放在 Session 裡。
這組 token 不會出現在 URL,也無法透過瀏覽器被攻擊者取得。

Laravel 接下來會要求「表單或 AJAX 請求」在送資料時,必須同時把這個 token 帶回來給伺服器比對。

表單提交的狀況

在 Blade 中加入:

@csrf
    

Laravel 會自動:

  • 把 token 注入進你的 <form>
  • 把 token 與 Session 裡的值比對
  • 不一致就直接拒絕請求

只要加上這一行,攻擊者就無法偽造請求,因為他根本拿不到這個 token。

JavaScript / Axios / Fetch 的狀況

你的專案使用這段:

<meta name="csrf-token" content="{{ csrf_token() }}" />
    

這表示你是透過 JS 發送 POST/PUT/DELETE 等請求。
Laravel 建議用這種方式將 token 放進 header,並由前端在每次請求時帶上:

axios.defaults.headers.common['X-CSRF-TOKEN'] = 
    document.querySelector('meta[name="csrf-token"]').content;
    

Laravel 的 VerifyCsrfToken middleware 會:

  • 找到 header 裡的 token
  • 與 Session 的 token 比對
  • 若不同 → 拒絕請求並回傳 419 錯誤

也就是說:

攻擊者雖然能利用 Cookie,但永遠拿不到你 meta 裡的 token,因此請求仍然會被擋下。

(官方文件佐證: https://laravel.com/docs/master/csrf

二、如果你用的是「純 PHP」沒有任何框架

這是很多工程師最擔心的情境。
但其實核心概念完全一樣:你只需要自己做一個 token,並在伺服器端比對即可。

以下是最穩定、也是企業專案中最常用的作法:

在顯示表單時產生 token,並存到 Session

session_start();

$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
    

然後在表單中放:

<input type="hidden" name="csrf_token" value="<?php echo $token; ?>">
    

這樣只有使用者本人看到的表單裡才會有 token,攻擊者無法提前偷到。

提交表單時比對 token

session_start();

if (!isset($_POST['csrf_token']) || 
    $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die("CSRF validation failed");
}
    

攻擊者即使能讓瀏覽器帶出 Cookie,也沒有辦法偽造這一段資料。

token 用過就刷新

unset($_SESSION['csrf_token']);
    

避免攻擊者利用舊 token。

三、兩者共同的重點:攻擊者拿不到 token,因此請求無法偽造

不論你是用 Laravel 或純 PHP:

  • 使用者能取得 token
  • 攻擊者不能取得 token
  • 請求要有 token 才會被接受
  • Cookie 再怎麼被利用,也沒 token 就作不了決定性修改

這就是 CSRF 防禦的核心精神。

什麼情況需要 CSRF 防禦?什麼情況不需要?

在理解 CSRF 的攻擊流程後,很多人會出現一個共同疑問:
「只要是表單,是不是都要做 CSRF 防護?」
真正的答案其實比多數人想像的更簡單

不是。

CSRF 能成立的前提只有一個:
攻擊者可以利用使用者「已登入」的狀態來偽造操作。

也就是說,只要一個系統依賴 Cookie 或 Session 來辨識身份,
攻擊者就有機會在使用者不知情的情況下,讓瀏覽器帶著這份身分發出偽造請求。

因此 CSRF 防禦不是看「有沒有表單」,而是看「有沒有登入」。

哪些情況一定要防 CSRF?哪些不需要?

需要 CSRF 防禦的情況(高風險)

只要系統必須確認「使用者是誰」,就必須防 CSRF,例如:

  • 會員中心編輯個人資料
  • 電商中的送單、更新購物車
  • 後台文章新增、刪除、修改
  • 帳號安全設定(修改 email / 密碼)
  • 財務相關操作(支付、餘額、轉帳)
  • 任何只允許登入後才能發出的請求

🔸 共同特色:伺服器會依 Cookie 判斷身分 → 高風險、一定要防

不需要 CSRF 防禦的表單(低風險)

如果系統沒有登入機制,例如:

  • 聯絡我們表單
  • 報名表單
  • 詢價表單
  • 未登入的留言表單
  • 不需要 Session 的單純提交流程

攻擊者就算偽造,也只會:

  • 送垃圾資料
  • 觸發 email 通知
  • 塞假報名

這類問題不是 CSRF,而是:

  • spam
  • bot
  • API 濫用

✔ 應採用:reCAPTCHA、honeypot、rate limit、email 驗證

一句話記住 CSRF 的適用情境

有登入 → 一定要防 CSRF
沒登入 → 不需要 CSRF(但要防垃圾與機器人)

如果你的系統依賴 Cookie 辨識使用者身份,那 CSRF 會是你每一支 API 的基本防線。
如果你的表單不牽涉登入,就不會被 CSRF 利用,但仍需要其他方法維持乾淨的資料品質。

💬 一起補足更多 CSRF 實務案例

每個團隊、每個專案的登入流程和 API 設計都不太一樣,
CSRF 在不同架構下的處理方式,也可能完全不同。

歡迎在下方分享你的做法或想法,也期待看到其他工程師如何在不同框架中處理這件事。
有更多實務案例,這篇文章才能更完整。

我要分享經驗
返回頂端