「攻击者准备好一个 ID,受害者却用它完成了登录」——这就是会话固定。本文讲解它的原理与可靠的防御方法(不公开攻击步骤)。
为什么会成立(原理)
关键在于「登录前后 session ID 不变」这种设计。只要它不变,攻击者在登录前就已知的 ID,在登录后仍会被当作「已认证」而通行。
它有时会与 CSRF 或 XSS 组合使用,但会话固定本身的本质只有一点:「登录时没有重新生成 ID」。
防御:登录时重新生成 ID
登录成功时重新生成 session ID(最重要)
不接受通过 URL 指定 session ID
加固 Cookie 属性
HttpOnly(JS 无法读取)、Secure(仅 HTTPS)、SameSite(抑制从其他站点发起的发送)。把相关的劫持路径一并削弱。设置合理的失效
本站观点:别关掉框架的『重新生成』
会话固定不需要自己精心设计的对策,靠「登录时重新生成 ID」这一招基本就能封堵。重要的是不要不小心关掉、也不要忘记调用框架已经准备好的这个机制。与其自己实现一套会话管理,不如依靠经过实战检验的实现的默认行为,更安全。本站坚持「认证和密钥相关的东西不自己造、不关掉默认的安全侧」这一原则。与 IDOR 一样,认证、授权相关的关键,就是「靠机制让它每次都生效」。
延伸阅读
FAQ
Q会话固定和会话劫持有什么区别?
会话劫持(hijacking)是「窃取」别人已经发出的 session ID 的攻击。会话固定(fixation)正相反,是攻击者先把「自己已知的 ID」交给受害者使用,等待受害者用该 ID 登录的攻击。它的特点不是窃取,而是让一个一开始就已知的 ID 变成已认证状态。
Q最有效的防御是什么?
就是『在登录的那一刻重新生成 session ID』。许多框架和会话库都有这个功能(session regenerate / renew),在认证成立的时刻丢弃旧 ID 并发出新 ID。仅此一项,攻击者事先埋下的 ID 就会失效。在权限提升的操作(如提升为管理员等)时也要重新生成。
Q为什么把 session ID 放进 URL 很危险?
ID 一旦出现在 URL 中,就容易通过链接分享、Referer、日志、浏览器历史泄露给第三方,成为攻击者让受害者踩中「想要固定的 ID」的入口。session ID 应当用 Cookie 处理而不是 URL 参数,并且不接受通过 URL 指定 ID,这样才安全。