名詞解釋

工作階段固定(Session Fixation)是什麼 — 讓使用者用攻擊者準備好的 ID 登入的漏洞

工作階段固定是攻擊者讓受害者使用預先準備的 session ID,待其登入後用同一 ID 冒充的攻擊。圖解原理,並說明主要防禦:登入時重新產生 session ID、不從 URL 接收 ID、設定 Cookie 屬性。

發布於 2026-06-11 更新於 2026-10-06 閱讀時間 3 分鐘
本頁內容

工作階段固定是指受害者用攻擊者準備好的 ID 完成了登入。本文講解它的原理與可靠的防禦方法(不公開攻擊步驟)。

為什麼會成立(原理)

原因在於「登入前後 session ID 不變」這種設計。只要它不變,攻擊者在登入前就已知的 ID,在登入後仍會被當作「已認證」而通行。

① 攻擊者讓受害者使用「某個 session ID」(透過連結等)
↓ 受害者就用那個 ID 登入
② ID 沒有被重新產生=同一個 ID 變成「已認證」
↓ 攻擊者一開始就知道那個 ID
③ 用同一個 ID 存取=冒充受害者
如果登入後 ID 不變,攻擊者事先已知的 ID 就會原樣變成已認證狀態。

它有時會與 CSRF 或 XSS 組合使用,但工作階段固定本身的本質只有一點:「登入時沒有重新產生 ID」。

日本 IPA(資訊處理推進機構)的指南《安全なウェブサイトの作り方》把它當作「工作階段管理不當」的一種,並指出所有具備登入功能的網站都需要留意。其根本解決方法是在登入成功後開始新的工作階段。

工作階段固定、工作階段劫持與 CSRF 的比較

這三者容易混淆。它們都濫用已登入的狀態,但攻擊者手上有什麼、哪種防禦有效並不相同。

項目工作階段固定工作階段劫持CSRF
攻擊者手上有什麼自己準備的 ID(一開始就知道)竊得的、已發出的 ID完全沒有 ID
受害者身上發生什麼用被埋下的 ID 登入已發出的 ID 被竊被迫送出非本意的請求
主要防禦登入時重新產生 IDHttpOnly/Secure、防止 XSS、縮短有效期CSRF Token、SameSite

工作階段固定是只要一個步驟——登入時重新產生 ID——就能從根本解決的那一個。

防禦:登入時重新產生 ID

1

登入成功時重新產生 session ID(最重要)

在認證成立的那一刻,丟棄舊 ID 並發出新的 session ID(許多框架的 session regenerate / renew)。事先埋下的 ID 立即失效。在權限提升的操作(如提升為管理員等)時也要重新產生。
2

不接受透過 URL 指定 session ID

session ID 要用 Cookie 處理,忽略從 URL 參數指定的 ID。堵住攻擊者讓受害者使用「想要固定的 ID」的途徑。
3

設定 Cookie 屬性

給工作階段 Cookie 加上 HttpOnly(JS 無法讀取)、Secure(僅 HTTPS)、SameSite(抑制從其他站點發起的傳送)。把相關的劫持路徑一併削弱。
4

設定合理的失效

透過固定時長、登出、修改密碼使工作階段失效。不讓被固定的 ID 長期有效。

OWASP 的 Session Management Cheat Sheet 建議在每次權限變化時重新產生 ID,並採用只接受伺服器自己產生之 ID 的「嚴格(strict)」機制。採用外部帶進來的未知 ID 的「寬鬆(permissive)」機制,會留下讓攻擊者選定的 ID 被接受的餘地。

常見框架的預設行為

多數框架只要使用標準的登入功能,就會自動重新產生 ID。風險出現在自己撰寫登入處理,或關掉預設保護的時候。

環境預設行為自己撰寫時要確認的事
PHP(原生工作階段)不會自動重新產生;session.use_strict_mode 預設為 0登入成功時呼叫 session_regenerate_id(true);把 use_strict_mode 設為 1
Laravel使用 starter kit 或 Fortify 時,認證時會自動重新產生若手寫登入,呼叫 $request->session()->regenerate()
Spring Security預設開啟(Servlet 3.1 以上為 changeSessionId)確認沒有人設定了 sessionFixation().none()

在 PHP 中,透過 URL 傳遞 session ID 的設定(啟用 session.use_trans_sid、停用 session.use_only_cookies)已在 PHP 8.4 被列為不建議使用。若沿用舊的設定檔,請重新檢查。

如何檢查自己的網站

在你管理的網站上確認以下四點。只需要開發人員工具。

  1. 在開發人員工具的「Application」(Firefox 為「儲存空間」)記下工作階段 Cookie 的值,登入後再看一次。如果沒有變,表示登入時沒有重新產生 ID
  2. 確認登入頁與登入後的 URL 中沒有 PHPSESSID= 或 ;jsessionid= 之類的 session ID
  3. 在同一面板確認工作階段 Cookie 有 HttpOnly、Secure 與 SameSite
  4. 登出後把舊的 Cookie 值放回去並重新載入;確認不會再次變成登入狀態

Cookie 屬性也可以用網站安全健檢檢查(對象為已確認所有權的網站)。每次修改登入流程時,把第 1 項放進自動化測試,就能在重新產生被拿掉時立刻察覺。

本站觀點:別關掉框架的『重新產生』

工作階段固定不需要自己精心設計的對策,靠「登入時重新產生 ID」這一個步驟基本就能防止。重要的是不要不小心關掉、也不要忘記呼叫框架已經準備好的這個機制。與其自己實作一套工作階段管理,不如使用經過驗證的實作的安全預設,更安全。本站堅持「認證和金鑰相關的東西不自己造、不關掉預設的安全側」這一原則。與 IDOR 一樣,認證、授權相關的關鍵,就是「靠機制讓它每次都生效」。

出處(一手資料)

  • IPA「安全なウェブサイトの作り方」1.4 セッション管理の不備(日文)— ipa.go.jp(登入後開始新的工作階段;不把 ID 放進 URL)
  • OWASP Session Management Cheat Sheet — cheatsheetseries.owasp.org(權限變化時重新產生、strict 機制、Cookie 屬性)
  • MITRE CWE-384: Session Fixation — cwe.mitre.org
  • PHP Manual, "Runtime Configuration"(工作階段)— php.net(use_strict_mode 等的預設值;8.4 的不建議使用項目)
  • Laravel 文件 "HTTP Session" — laravel.com / Spring Security, "Authentication Persistence and Session Management" — docs.spring.io

延伸閱讀

分類編號

CWE 對造成漏洞的弱點類型進行分類,MITRE ATT&CK 對攻擊者的技術進行分類。兩者皆由 MITRE 維護,廣泛用於標註漏洞資訊與偵測規則。

CWE(弱點類型)

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

FAQ

Q工作階段固定和工作階段劫持有什麼區別?
A

工作階段劫持(hijacking)是「竊取」別人已經發出的 session ID 的攻擊。工作階段固定(fixation)正相反,是攻擊者先把「自己已知的 ID」交給受害者使用,等待受害者用該 ID 登入的攻擊。它的特點不是竊取,而是讓一個一開始就已知的 ID 變成已認證狀態。

Q最有效的防禦是什麼?
A

就是『在登入的那一刻重新產生 session ID』。許多框架和工作階段函式庫都有這個功能(session regenerate / renew),在認證成立的時刻丟棄舊 ID 並發出新 ID。僅此一項,攻擊者事先埋下的 ID 就會失效。在權限提升的操作(如提升為管理員等)時也要重新產生。

Q為什麼把 session ID 放進 URL 很危險?
A

ID 一旦出現在 URL 中,就容易透過連結分享、Referer、日誌、瀏覽器歷程外洩給第三方,攻擊者就能藉此讓受害者使用「想要固定的 ID」。session ID 應當用 Cookie 處理而不是 URL 參數,並且不接受透過 URL 指定 ID,這樣才安全。

Q怎麼確認自己的網站是否容易受到工作階段固定攻擊?
A

在自己的網站上打開瀏覽器的開發人員工具,比較登入前後工作階段 Cookie 的值。如果登入後值仍相同,表示 ID 沒有被重新產生,需要修正。也請確認 URL 中沒有 session ID,以及 Cookie 已設定 HttpOnly、Secure 與 SameSite。

QPHP 有哪些設定能防止工作階段固定?
A

登入成功時呼叫 session_regenerate_id(true) 切換到新 ID。在 php.ini 中把 session.use_strict_mode 設為 1,讓伺服器拒絕不是自己發出的 ID(預設為 0)。session.use_only_cookies 保持預設的 1、session.use_trans_sid 保持預設的 0,讓 ID 永遠不會透過 URL 傳遞。

Q使用 JWT 時,還會發生工作階段固定嗎?
A

如果不使用伺服器端的 session ID,並在登入成功時發出全新的權杖,「讓事先選定的 ID 變成已認證」這種攻擊就很難成立。但如果登入前發出的權杖在登入後繼續被使用,就可能發生同樣的問題。不論採用哪種機制,原則都是在登入的那一刻發出新的識別碼。