修复PHP验证码可爆破漏洞的核心是服务端严格执行“用完即废+限时限次+绑定上下文”三重约束:校验后立即unset验证码Session、限制有效期(如2分钟)和尝试次数(如5次/IP)、绑定表单token等上下文,避免复用与暴力破解。

修复PHP验证码可爆破漏洞,核心是切断“一次获取、多次使用”的攻击链,同时让自动化工具难以持续尝试。关键不在验证码画得多好看,而在于服务端是否严格执行“用完即废+限时限次+绑定上下文”这三重约束。
强制单次验证并立即清除Session
很多漏洞源于验证码校验成功后未及时销毁Session中的值。攻击者抓到一个有效包,就能无限重放。
- 校验通过后必须调用 unset($_SESSION['vcode']),不能只设为空字符串(
$_SESSION['vcode'] = ''),否则提交空值仍可能绕过 - 若需记录验证状态,应使用独立的标记键(如
$_SESSION['vcode_used'] = true),并在校验逻辑开头就判断该标记是否存在 - 避免在验证码生成页(如 vcode.php)之外的地方重复调用
session_start()导致会话覆盖或延迟生效
限制验证窗口期与尝试次数
即使验证码本身难识别,如果有效期长达10分钟、允许100次错误尝试,照样能被暴力跑通。
- 生成验证码时,同时写入时间戳:
$_SESSION['vcode_time'] = time(); - 校验前先检查:
if (time() - $_SESSION['vcode_time'] > 120) { die('验证码已过期'); }(建议2分钟内) - 为每个IP或每个手机号/用户名维护独立计数器(存Redis更稳妥),连续失败5次即拒绝该标识后续请求,至少封禁15分钟
绑定关键上下文,防止跨请求复用
单纯靠Session ID不够——攻击者可复用同一会话下的多个验证码请求结果。
立即学习“PHP免费学习笔记(深入)”;
- 生成验证码时,将当前登录表单的唯一标识(如随机token或当前页面URL哈希)一并存入Session,并在校验时比对
- 避免把验证码直接塞进HTML源码或JS变量中;禁止前端拼接、计算或缓存验证码值
- 若使用AJAX加载验证码,确保每次请求都携带新鲜的CSRF token,且后端校验该token未被使用过
升级验证方式,降低机器识别成功率
图形验证码若仅含4位纯数字+简单噪点,OCR工具几秒就能批量识别。不求绝对防住,但要提高攻击成本。
- 优先采用滑动拼图、文字点选、语义问答等交互式验证,服务端需校验轨迹特征或答案逻辑,而非静态图片
- 若仍用图片验证码,增加扭曲、粘连、干扰线,字符集避开0/O/l/1等易混字,长度设为5–6位,支持大小写混合
- 对高频请求IP,自动降级为短信验证码(需配合频率控制,防轰炸)或要求人工审核



















