工作階段固定是指受害者用攻擊者準備好的 ID 完成了登入。本文講解它的原理與可靠的防禦方法(不公開攻擊步驟)。
為什麼會成立(原理)
原因在於「登入前後 session ID 不變」這種設計。只要它不變,攻擊者在登入前就已知的 ID,在登入後仍會被當作「已認證」而通行。
它有時會與 CSRF 或 XSS 組合使用,但工作階段固定本身的本質只有一點:「登入時沒有重新產生 ID」。
日本 IPA(資訊處理推進機構)的指南《安全なウェブサイトの作り方》把它當作「工作階段管理不當」的一種,並指出所有具備登入功能的網站都需要留意。其根本解決方法是在登入成功後開始新的工作階段。
工作階段固定、工作階段劫持與 CSRF 的比較
這三者容易混淆。它們都濫用已登入的狀態,但攻擊者手上有什麼、哪種防禦有效並不相同。
| 項目 | 工作階段固定 | 工作階段劫持 | CSRF |
|---|---|---|---|
| 攻擊者手上有什麼 | 自己準備的 ID(一開始就知道) | 竊得的、已發出的 ID | 完全沒有 ID |
| 受害者身上發生什麼 | 用被埋下的 ID 登入 | 已發出的 ID 被竊 | 被迫送出非本意的請求 |
| 主要防禦 | 登入時重新產生 ID | HttpOnly/Secure、防止 XSS、縮短有效期 | CSRF Token、SameSite |
工作階段固定是只要一個步驟——登入時重新產生 ID——就能從根本解決的那一個。
防禦:登入時重新產生 ID
登入成功時重新產生 session ID(最重要)
不接受透過 URL 指定 session ID
設定 Cookie 屬性
HttpOnly(JS 無法讀取)、Secure(僅 HTTPS)、SameSite(抑制從其他站點發起的傳送)。把相關的劫持路徑一併削弱。設定合理的失效
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 被列為不建議使用。若沿用舊的設定檔,請重新檢查。
如何檢查自己的網站
在你管理的網站上確認以下四點。只需要開發人員工具。
- 在開發人員工具的「Application」(Firefox 為「儲存空間」)記下工作階段 Cookie 的值,登入後再看一次。如果沒有變,表示登入時沒有重新產生 ID
- 確認登入頁與登入後的 URL 中沒有
PHPSESSID=或;jsessionid=之類的 session ID - 在同一面板確認工作階段 Cookie 有
HttpOnly、Secure與SameSite - 登出後把舊的 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