任意用户密码重置(六):应答中存在影响后续逻辑的状态参数
字数 1405 2025-08-18 11:37:12
任意用户密码重置漏洞分析:应答中存在影响后续逻辑的状态参数
漏洞概述
本教学文档分析了一种常见的密码重置逻辑漏洞,即服务端在密码重置流程中错误地将验证状态参数下发给客户端,而客户端依赖这些前端参数决定后续流程,导致攻击者可以通过篡改应答包中的状态参数实现任意用户密码重置。
漏洞原理
密码找回/重置流程通常包含三个关键步骤:
- 获取短信验证码
- 校验短信验证码有效性
- 设置新密码
漏洞核心在于第二步的验证结果状态处理不当:
- 正确做法:服务端应在校验通过后在服务器端保存状态(如通过session或cookie)
- 错误做法:服务端仅将校验结果状态下发客户端,后续流程依赖前端JS判断这些状态参数
攻击场景复现
案例一分析
目标网站:http://www.xx.cn/yy/action/forgot
攻击步骤:
-
攻击者使用自己的手机号(13908081024)完成正常密码找回流程,捕获成功应答包:
HTTP/1.1 200 OK ... {"status":"success","message":"验证通过"} -
针对目标用户(客服手机号13980808888)发起攻击:
- 输入目标手机号
- 获取短信验证码(攻击者不知道)
- 输入任意错误验证码(如123123)
- 拦截服务端返回的失败应答:
HTTP/1.1 200 OK ... {"status":"fail","message":"验证码错误"}
-
篡改应答包:
- 将失败应答替换为之前捕获的成功应答
- 修改状态参数:
"status":"fail"→"status":"success"
-
前端JS接收到"success"状态后,允许进入密码设置页面
-
攻击者设置新密码并提交,完成密码重置
案例二分析
目标网站:http://www.xx.cn/yy/forgot
差异点:
- 状态参数使用code字段而非status
- 成功状态码为"0000"
攻击步骤:
-
捕获正常流程成功应答:
{"code":"0000","message":"验证成功"} -
针对目标用户(13888888888):
- 输入错误验证码(如1234)
- 拦截失败应答:
{"code":"9999","message":"验证失败"}
-
篡改应答包:
- 将code从"9999"改为"0000"
-
系统允许设置新密码,完成重置
漏洞利用条件
- 密码重置流程依赖前端状态判断
- 服务端未在服务器端保存验证状态
- 应答包中的状态参数可被中间人篡改
- 无其他辅助验证机制(如二次验证)
防御措施
服务端加固方案
-
状态保存:
- 验证通过后在服务端保存状态(如session中设置
verify_passed=true) - 不要依赖前端传递的状态参数
- 验证通过后在服务端保存状态(如session中设置
-
请求验证:
- 每个步骤验证前置步骤是否完成
- 设置新密码前检查服务端保存的验证状态
-
防篡改机制:
- 对关键参数进行签名验证
- 使用HTTPS防止中间人攻击
-
限流措施:
- 限制短信验证码获取频率
- 限制验证码错误尝试次数
客户端加固方案
- 不要仅依赖前端JS判断流程状态
- 每个步骤向服务端确认前置条件是否满足
- 对关键操作进行二次确认
渗透测试方法
-
信息收集:
- 枚举密码重置流程的所有请求/应答
- 分析状态参数的传递方式
-
流程分析:
- 正常完成一次密码重置,记录所有交互
- 特别关注验证通过后的应答内容
-
篡改测试:
- 故意输入错误验证码
- 拦截应答并尝试修改状态参数
- 观察是否能绕过验证进入密码设置
-
状态验证:
- 检查服务端是否设置了验证状态cookie
- 尝试删除cookie后能否继续流程
总结
该类型漏洞的根源在于业务逻辑状态管理不当,将本应由服务端维护的状态下发给客户端,导致攻击者可以通过中间人攻击篡改状态参数。开发人员应始终遵循"服务端验证"原则,所有关键业务逻辑的判断都应在服务端完成,客户端仅作为展示层。