前言

對於從零實務經驗踏入職場的我來說,在參與開發流程的各個環節中,有一個領域是我完全始料未及的。那就是Web 系統的安全性。

在打造原創應用程式時幾乎不曾考量到的安全面,當它在自己參與的產品中實際成為問題時,我深刻體會到有必要進行基礎的深入理解。

這次我想一邊複習安全性的基礎,一邊整理自己學習到的、尤其覺得重要的 CSRF 攻擊手法與防禦方式,作為一篇學習紀錄。

目標是在下次再次遇到「CSRF 是什麼來著」時,能回顧它是以什麼機制、針對什麼弱點、又有哪些防禦措施。

Web 系統安全性的基礎

什麼是資訊安全

所謂安全性,就是維持資訊的「機密性」「完整性」「可用性」。
以下逐一來看。

  • 機密性
    只有被允許存取的人才能存取該資訊。不要把資訊讓無關的人看見。
  • 完整性
    確保資訊沒有被竄改或刪除。
  • 可用性
    在需要時能隨時存取,並保持可用狀態。

即使只是籠統地說「做安全對策」,實作時也應該先意識到這些面向。

風險・威脅・弱點

對於這些常常混用的詞,也想重新建立正確認知。

  • 風險
    發生某種損失的可能性
  • 威脅
    讓風險成真的因素
  • 弱點
    對威脅而言的脆弱之處

以具有寄送電子郵件功能的 Web 應用程式為例,可以這樣描述:

「面對惡意使用者想大量執行寄信 API 的威脅,由於系統沒有設定單位時間內寄送次數上限,並且會接受大量請求,因此存在能夠承受大量請求的弱點,結果大量郵件被送出,導致寄信成本上升與網域信譽下降等影響的風險變得具體化。」

在掌握基礎後,接下來想深入理解實際遇到並處理過的威脅:CSRF。

什麼是 CSRF

CSRF(Cross-Site Request Forgery,跨站請求偽造)是利用已登入使用者的權限,向 Web 應用程式送出使用者本人並未打算發出的請求的一種攻擊。

因為不太容易直觀理解,所以用圖來表示的話:
Codex 圖片 2026年9月29日 17_30_39.png

大致就是這樣。

重點在於中央的攻擊者並不是竊取了認證資訊。

由於使用者的瀏覽器中保存著認證 Cookie,當使用者打開惡意網站時,瀏覽器會自動把 Cookie 附加到該網站送出的請求上,因此不論使用者是否真的在操作,從伺服器端看起來都像是本人發出的通訊。

CSRF 攻擊的特徵在於,已認證與本人親自操作是兩回事。

再回頭套用剛才的「威脅・弱點・風險」來整理看看:

  • 威脅
    攻擊者讓登入中的使用者
    送出非預期的請求
  • 弱點
    沒有充分驗證請求是否來自正規畫面
  • 風險
    使用者不想要的資料變更或
    寄信等操作,以使用者權限被執行

可以這樣重新表述。

我們工程師在與 AI 來回討論、釐清風險、盤點威脅之後,必須有意識地實作出真正能封住弱點的防護。

CSRF 的目標處理

那麼,要防 CSRF,首先必須知道它會針對什麼下手。整理一下大致如下:

  • 寄送電子郵件
  • 變更密碼
  • 修改註冊資料
  • 購買商品
  • 刪除資料
  • 邀請使用者

這類會改變狀態的處理特別容易成為目標。

與其只是單純透過 GET 請求讀取資料,攻擊者更常做的是讓受害者的權限去執行某些操作。也就是說,攻擊的重點在於能改變伺服器狀態的處理,例如資料更新、刪除、送出等。

CSRF 的防禦措施

在了解 CSRF 攻擊的特徵、目標處理與手法之後,接下來來思考實際的防禦。
CSRF 之所以能成立,其中一個主要原因是瀏覽器會在某些條件下,自動把用於認證的 Cookie 附加到請求中。
因此在設計防禦時,需要從以下多個角度思考:

  1. 盡可能不要讓 Cookie 從其他網站被帶出去
  2. 驗證請求來源是否可信
  3. 不要讓不同 Origin 的 JavaScript 任意操作 API
  4. 驗證該請求是否來自正規畫面

下面來看各種防禦方式的例子。

1. SameSite Cookie

要避免 Cookie 從別的網站被送出,這個機制很有效。

Cookie 有一個名為 SameSite 的屬性,可以由瀏覽器端限制在跨網站請求時是否附帶 Cookie。

主要有三種:

  • Strict
    最嚴格的設定。原則上,從其他網站發起的請求不會送出 Cookie。
  • Lax
    比 Strict 寬鬆。只要在同一網站內就會正常送出 Cookie;即使從其他網站來,只要是某些條件下的頂層正常導向也會送出。不過,一般跨網站的 POST、PUT、DELETE 等請求不會送出 Cookie,因此能有效防止多數 CSRF 攻擊。
  • None
    不論是跨網站還是同網站都會送出 Cookie。限制最弱。

實務上常用的是兼顧安全性與便利性的 Lax,記得要掌握。
Lax 的意思是:允許一般連結導向,但對 POST 等操作更嚴格。

Set-Cookie: session=abc123; SameSite=Lax

透過在 HTTP 回應標頭加上這類設定來防範。

2. Better Auth 的 Trusted Origins

要判斷請求來源是否可信,需要驗證 Origin。
所謂 Origin,大致可以把

https://example.com:443

這個網域視為由下列組合構成:

scheme → https
host   → example.com
port   → 443

記住這一點之後,就可以在應用程式端只信任被允許的 Origin,拒絕來自未預期網站的請求。

比較知名的是 Better Auth 這個框架中的 trustedOrigins 設定:

const auth = betterAuth({
  trustedOrigins: [
    "https://example.com",
  ],
})

用這種方式明確指定某個 Origin「可以信任」。

3. CORS

若要避免不同 Origin 的 JavaScript 自由存取 API,就會涉及 CORS(Cross-Origin Resource Sharing,跨來源資源共享) 這個機制。

在實際 Web 應用中,前端與 API 位於不同 Origin 的情況也很常見。
這時候,API 端透過 CORS 告訴瀏覽器:「來自這個 Origin 的 JavaScript 存取是可以允許的。」

以 Hono 為例,可以這樣設定:

import { cors } from "hono/cors"

app.use(
  "/api/*",
  cors({
    origin: ["https://app.example.com"],
    allowMethods: ["GET", "POST", "OPTIONS"],
    credentials: true,
  })
)

Hono 可以把 CORS 設定作為 Middleware 套用,因此即使攻擊者從自己準備的其他 Origin 嘗試用 JavaScript 存取 API,只要不是 CORS 允許的網域,瀏覽器就會限制跨來源存取,進而形成防護。

對於 DELETE 等特定請求,還會有透過 OPTIONS 方法先送出 Preflight Request 的限制。

4. CSRF Token

最後,作為確認請求是否由正規使用者發出的代表性方法,就是 CSRF Token。雖然我在實務上還沒實際碰過,但因為它是代表性的 CSRF 防禦方式,所以這裡也一併介紹。

CSRF Token 是伺服器產生的一個難以被第三方猜測的隨機值。

例如,當使用者開啟正規網頁時,從伺服器收到一個 Token,如下:

csrfToken = "a8f3c9..."

接著在送出會變更資料的 POST、PUT、DELETE 等請求時,也一併把這個 Token 帶上。

POST /api/profile

X-CSRF-Token: a8f3c9...

伺服器端會檢查是否有 CSRF Token,並驗證它是否與伺服器所發放的 Token 一致。
CSRF Token 能有效發揮作用的原因在於:

「攻擊者雖然可以讓受害者瀏覽器送出請求,但在正確實作 CSRF 防護的情況下,無法得知正規的 CSRF Token。」

這不只是因為有 Cookie,而是必須再加上 CSRF Token,才能真正建立起能確認是使用者本人意圖操作的防線。

防禦措施整理

SameSite
→ 控制跨網站請求是否附帶 Cookie

trustedOrigins
→ 驗證請求來源的 Origin 是否可信

CORS
→ 控制是否允許不同 Origin 的 JavaScript 進行跨來源存取

CSRF Token
→ 驗證請求中是否包含正規的 Token

image.png

雖然它們看起來是相似的防禦手段,但實際上各自守護的層次並不相同。
重要的是,面對 CSRF 攻擊時不要只依賴單一機制,而是要建立多重防線,實現多層防禦。

結語

因為我原本對安全性幾乎一無所知,所以先整理了各個術語所代表的意義,再進一步深入實際做過對策的 CSRF,最後彙整出防禦方法。當然,除此之外還有許多其他防禦方式,因此我也體會到,根據自身應用程式的架構選擇適合的防禦手段非常重要。
如果有機會,之後我也想在下一篇文章中介紹 XSS 與 SQL Injection,並連同安全性標頭的機制一起輸出成學習筆記。

參考文獻

  • 小林恭平・坂本陽 著、佐佐木拓郎 監修《插圖圖解式 這一本全部搞懂 Web 技術的基礎》SB Creative
  • 平野昌士 著、はせがわようすけ・後藤つぐみ 監修《前端開發的安全入門:不能因為不知道就算了的弱點對策必備知識》翔泳社
  • OWASP — Cross-Site Request Forgery Prevention Cheat Sheet

株式会社辛西亞

株式会社 xincere 正在招募沒有實務經驗的工程師與學生工程師實習生,並一起工作。
※ 關於辛西亞的工作方式可參考這裡

在辛西亞,每年約有 100 位左右沒有實務經驗的應徵者參加技術面試。


原文出處:https://qiita.com/Pigeon_gate/items/b33b4e337c15dddae20a


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝60   💬2  
870
🥈
NewsData
2
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登