术语表

会话固定(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 为「Storage」)中记下会话 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(权限变化时重新生成、严格机制、Cookie 属性)
  • MITRE CWE-384: Session Fixation — cwe.mitre.org
  • PHP Manual, "Runtime Configuration"(会话)— php.net(use_strict_mode 等的默认值、8.4 的弃用项)
  • Laravel docs, "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,并且在登录成功时发出新的 token,那么「让事先选好的 ID 变成已认证」这种攻击就很难成立。但如果登录前发出的 token 在登录后继续被使用,同样的问题仍可能发生。无论采用哪种机制,原则都是在登录那一刻发出新的标识符。