在 Web 应用程序的安全评估中,退出登录功能常被误认为只是简单的前端操作。许多系统在用户点击“退出”后,仅通过前端脚本清除了浏览器的 LocalStorage 或覆盖了 Cookie,并在界面上重定向至登录页;然而,后端的会话状态并未销毁,原有的 Session ID 或 JWT 凭证依然能够正常访问受保护资源。依据 OWASP Web Security Testing Guide (WSTG-SESS-06) 的规范,彻底的会话终止必须在服务端完成凭证撤销。

测试目标、范围与安全控制
本测试旨在验证目标系统在触发登出操作后,服务端是否对相关会话凭证实施了真正的废止,排查 CWE-613(不充分的会话过期)缺陷。为确保测试合规并规避对业务环境造成影响,测试过程必须严格遵循以下控制边界:
- 测试账户限制:仅使用渗透测试授权书中明确分配的专用低权限测试账户,严禁对生产用户或未授权账户实施登出测试。
- 请求影响控制:后续重放验证仅选用低影响、幂等的只读请求(例如获取个人资料摘要
GET /api/v1/user/profile),严禁使用涉及资产变更、数据删除或状态流转的敏感业务接口。 - 中止与清理规则:一旦确认原凭证在退出后仍能成功调用受保护接口,即证明存在漏洞,应立即停止持续发包,防止触发防护机制或造成冗余日志。测试结束后,需手动在测试后台执行全量登出并重置该账户密码,彻底销毁临时凭证。
环境准备:双客户端环境隔离
仅凭单个浏览器的“退出再后退”测试极易受到本地缓存(如浏览器 Disk/Memory Cache)或前端路由守卫的干扰,得出不准确的结论。使用双客户端隔离验证是确认服务端状态最可靠的方法:
- 客户端 A(操作端):用于建立会话、提取请求样本并最终触发注销操作。可使用 Chrome 正常窗口,配合本地代理工具(如 Burp Suite 或 OWASP ZAP)。
- 客户端 B(对照端 / 监听端):用于模拟多端会话或承载独立请求的重放环境。可使用 Firefox 无痕窗口或命令行工具(如 cURL、Postman),与客户端 A 完全隔离存储区。
双客户端验证执行步骤
步骤一:侦察会话机制与基线采集
首先登录客户端 A,在代理工具中观察身份凭证的传递形式(如 Cookie 中的 JSESSIONID、PHPSESSID,或请求头中的 Authorization: Bearer <Token>)。
通过客户端 A 访问一个只读受保护资源,记录基线响应:
GET /api/v1/user/profile HTTP/1.1
Host: target.example.com
Authorization: Bearer eyJhbGciOi...[客户端A的凭证]
Accept: application/json
预期应返回 HTTP/1.1 200 OK 及对应的用户只读信息。将该完整请求保存至重放器(Repeater)作为比对基准。
步骤二:单端退出与原凭证重放测试
在客户端 A 上点击界面的“退出登录”按钮,拦截并观察登出请求的结构:
POST /api/v1/auth/logout HTTP/1.1
Host: target.example.com
Authorization: Bearer eyJhbGciOi...[客户端A的凭证]
Content-Type: application/json
{}
记录该请求的响应。注意服务端是否下发了清除 Cookie 的指令(如 Set-Cookie: session=; Max-Age=0)。
完成登出后,切勿使用浏览器界面重试,而是直接在代理工具或命令行终端中使用刚才记录的客户端 A 原凭证重放受保护资源请求:
curl -s -i -k -X GET "https://target.example.com/api/v1/user/profile"
-H "Authorization: Bearer eyJhbGciOi...[客户端A已退出的凭证]"
- 预期合规响应:返回
HTTP/1.1 401 Unauthorized或403 Forbidden,证明服务端已注销该凭证。 - 异常风险响应:依然返回
HTTP/1.1 200 OK且内容完整,说明系统仅执行了客户端跳转,服务端未同步失效会话。

步骤三:多端并发与全端退出差异验证
Web 架构中普遍存在单端登出与“退出所有设备”两种设计,需在授权测试中明确区分预期行为:
- 保持客户端 A 登录,同时在客户端 B(无痕窗口)使用同一账号登录,使系统内同时存在两套有效凭证(Token A 与 Token B)。
- 在客户端 A 上触发常规“退出登录”。
- 在客户端 B 上重放只读接口:
- 若业务定位为“仅退出当前设备”,Token B 仍应为
200 OK,而 Token A 必须为401 Unauthorized。 - 若业务触发了“退出全部已登录设备”(或修改密码引发全局退出),则客户端 A 与 B 的凭证应均变为
401 Unauthorized。
证据记录与分析要素
在渗透测试报告中,不得仅截图前端重定向后的登录界面,必须记录底层完整的通信证据链:
| 证据字段 | 记录重点 | 示例说明 |
|---|---|---|
| 测试时间戳 | 精确到秒的操作时刻 | 2025-05-10T14:20:05Z |
| 登出触发报文 | 请求方法、URL、认证凭证与后端响应头 | 验证是否有服务端清除意图 |
| 重放测试报文 | 退出完成后立即发送的受保护接口请求 | 包含完整请求头与参数 |
| 重放响应报文 | 状态码与响应体数据摘要 | 重点展示是否仍返回 200 OK 及受保护数据 |
| 凭证类型 | 有状态 Cookie 或是无状态 JWT | 用于辅助开发判断失效失效根因 |
风险评估与服务端加固建议
若退出登录后凭证仍能调用受保护接口,属于典型的身份认证与会话管理失效。攻击者若通过中间人劫持、跨站脚本(XSS)或公共终端缓存获取到历史凭证,即使合法用户已主动登出,攻击者仍能在凭证生命周期内持续访问系统,使安全退出机制完全形同虚设。
服务端整改方案
- 有状态 Session(Cookie/Session-ID):
后端框架在接收到登出请求后,必须主动执行会话销毁方法(如 Spring Security 的 session.invalidate() 或 PHP 的 session_destroy()),同时在存储介质(Redis/数据库)中删除对应键值,并下发设置 Max-Age=0 或 Expires 过期的响应头覆盖客户端 Cookie。
- 无状态凭证(JWT):
由于标准的 JWT 一旦签发在到期前由签名保证有效,纯前端清除并不等同于服务端撤销。服务端应采用以下策略之一:
- 黑名单机制:在 Redis 等高性能缓存中维护一个已登出 Token 的 JTI(JWT ID)黑名单,存活期设为该 Token 的剩余有效期。网关或鉴权中间件每次验证签名后,需核对黑名单。
- 双 Token 刷新架构:将访问凭证(Access Token)的有效期压缩至极短(如 5 至 15 分钟),登出时仅需在服务端数据库彻底吊销刷新凭证(Refresh Token),使后续刷新通道阻断。
回归验证流程
开发团队实施修复后,测试人员应使用相同版本的测试用例执行回归:重新登录测试账号,保存有效只读接口请求;调用退出功能;以毫秒级间隔立刻重放受保护资源,确认服务端返回 401 Unauthorized;同时检查重放携带空凭证、伪造凭证与旧凭证三者的响应差异,确保授权检验逻辑严密闭环。
- Chrome
- it2021
- it2021.com
- OWASP
- test
- 命令行工具
- 渗透测试

1F
JWT 这种无状态凭证最容易假登出