在 Web 安全领域,SQL 注入、XSS、命令执行等传统漏洞随着框架和 WAF 的成熟逐渐被压缩,而逻辑漏洞却始终是渗透测试中最高效的突破口之一。逻辑漏洞不依赖代码层面的语法缺陷,而是利用业务流程设计上的疏忽,往往能直接造成越权访问、资金损失和账户劫持。本文从实战角度出发,围绕验证码绕过、支付篡改和密码重置缺陷三类高频逻辑漏洞展开分析。
一、验证码绕过:不只是“识别”的问题
验证码的设计初衷是区分人与机器,但在实际业务中,验证码逻辑的缺陷远比识别难度更致命。
1.1 验证码未绑定会话
最常见的缺陷是验证码校验与用户会话脱钩。服务端生成验证码后存入全局变量或独立缓存,校验时只比对用户提交的值,而不检查该验证码是否属于当前会话。
攻击方式:攻击者在自己的会话中获取验证码,然后在目标受害者的请求中携带该验证码完成校验。如果服务端不校验 Session ID 与验证码的绑定关系,即可绕过。
POST /api/verify HTTP/1.1
Host: target.com
Cookie: JSESSIONID=attacker_session
...
code=1234&phone=13800000000
若服务端仅验证 code 是否正确,而不检查该 code 是否由 attacker_session 生成,则短信轰炸、批量注册等攻击成为可能。
1.2 验证码复用与失效机制缺失
部分系统在校验成功后不销毁验证码,导致同一验证码可重复使用。在密码重置、支付确认等场景中,这意味着攻击者可以截获一次验证码后无限次调用接口。
测试方法:获取验证码后,连续提交同一验证码多次,观察是否均返回成功。若均成功,说明验证码未设置一次性失效。
1.3 客户端校验绕过
部分应用将验证码校验逻辑放在前端 JavaScript 中,服务端仅依赖前端传来的 isVerified=true 标志。攻击者直接构造请求跳过前端校验即可。
// 前端伪代码
if (inputCode === serverCode) {
document.getElementById('verified').value = 'true';
}
绕过方式:直接发送 verified=true 参数,无需提交验证码。
1.4 空验证码与万能验证码
某些系统在验证码字段为空时跳过校验,或存在硬编码的“万能验证码”(如 0000、8888)。这类问题在测试环境中常见,但若配置未清理便上线,便成为严重隐患。
二、支付篡改:金额、数量与状态的三重博弈
支付逻辑漏洞直接关联资金安全,是漏洞挖掘中赏金最高的类别之一。常见缺陷集中在金额篡改、数量篡改和支付状态篡改三个方向。
2.1 金额篡改
服务端信任客户端提交的金额参数,未在后台重新计算。攻击者将 amount 从 100.00 改为 0.01,以极低价格完成支付。
POST /api/pay HTTP/1.1
...
{"orderId":"20240101001","amount":0.01,"productId":"P1001"}
防御要点:服务端应根据 productId 和数量重新计算应付金额,忽略客户端传入的 amount。
2.2 数量篡改与负数攻击
在涉及数量参数的场景中,攻击者可将 quantity 改为负数,导致总价变为负值,从而在退款或积分场景中获利。
{"productId":"P1001","quantity":-1,"price":100}
若服务端计算逻辑为 total = quantity * price,则 total = -100,攻击者可能获得反向资金流入。测试时需关注数量、单价、总价三者是否在服务端独立校验。
2.3 支付状态篡改
部分系统在支付回调中仅依赖前端返回的 status=success,而不验证第三方支付平台的签名。攻击者伪造回调请求,直接将订单标记为已支付。
POST /api/payment/callback HTTP/1.1
...
{"orderId":"20240101001","status":"success","sign":"..."}
若签名校验缺失或密钥泄露,攻击者可零成本完成订单。正确做法是服务端主动向支付平台查询订单状态,或严格验证回调签名。
2.4 并发与条件竞争
在高并发场景下,攻击者同时发起多笔支付请求,利用服务端库存扣减或优惠券核销的竞态条件,实现“一份钱多份货”或重复使用优惠券。这类漏洞需要通过并发请求工具(如 Burp Intruder 的 Turbo Intruder 插件)进行测试。
三、密码重置缺陷:账户劫持的捷径
密码重置功能是账户安全的核心环节,其逻辑缺陷往往直接导致账户被接管。
3.1 重置令牌可预测
部分系统使用时间戳、用户 ID 或简单哈希生成重置令牌,攻击者可通过枚举或推算获取他人令牌。
token = md5(username + timestamp)
若时间戳精度为秒,且用户名已知,攻击者可在短时间内暴力枚举令牌。
3.2 令牌未绑定用户
重置链接中的令牌未与用户身份绑定,攻击者获取自己的令牌后,修改请求中的用户 ID 即可重置他人密码。
POST /api/reset-password HTTP/1.1
...
{"token":"abc123","userId":"victim_id","newPassword":"hacked"}
若服务端仅验证 token 有效性,而不检查 token 与 userId 的对应关系,即可实现任意用户密码重置。
3.3 重置凭证泄露
部分系统在重置流程中通过响应体、URL 参数或 Referer 头泄露令牌。例如,重置页面加载第三方资源时,令牌可能通过 Referer 头泄露给外部站点。
3.4 邮箱/手机号篡改
在重置流程中,攻击者将接收验证码的手机号或邮箱修改为自己的,从而接收本应发送给受害者的重置凭证。
POST /api/send-reset-code HTTP/1.1
...
{"phone":"attacker_phone","userId":"victim_id"}
若服务端未校验 phone 是否属于 userId 对应的用户,即可劫持重置流程。
3.5 响应差异与用户枚举
部分系统在重置时对存在的用户和不存在的用户返回不同响应,攻击者可据此枚举有效账户,为后续攻击提供目标列表。
四、防御建议
针对上述逻辑漏洞,开发与安全团队应从以下方面加强防护:
- 服务端主导校验:所有关键逻辑(金额计算、状态判断、权限校验)必须在服务端完成,不信任客户端任何参数。
- 绑定会话与用户:验证码、重置令牌等凭证必须与当前会话和用户身份强绑定,并设置一次性失效。
- 签名与回调验证:支付回调必须验证第三方签名,或主动查询支付状态,避免伪造回调。
- 并发控制:对库存扣减、优惠券核销等操作加锁或使用原子操作,防止条件竞争。
- 统一响应:避免因响应差异泄露用户存在性等信息。
- 安全测试左移:在需求评审和开发阶段引入逻辑漏洞检查清单,减少上线后的风险。
逻辑漏洞的挖掘依赖对业务流程的深入理解,而非单纯的工具扫描。渗透测试人员应重点关注“参数是否可篡改”“状态是否可伪造”“凭证是否可复用”三个核心问题,才能在实战中高效发现高价值漏洞。
未经允许不得转载:任鹏个人博客 » 逻辑漏洞挖掘实战:验证码绕过、支付篡改与密码重置缺陷

