验证码防重放的关键是生成后立即绑定会话并销毁,而非字符生成方式;必须在验证前后严格管理session生命周期,确保值不出服务器、不存前端、及时过期与清除。

验证码生成后必须立即绑定会话并销毁
防重放的关键不是“怎么生成字母”,而是“生成之后谁还能用它”。只要验证码字符串生成后还留在内存或 Session 里没被清掉,攻击者就可能截获一次响应、反复提交——哪怕你用了 random_bytes() 生成强随机字符串也白搭。
常见错误是:生成完 $_SESSION['captcha'] 后,在验证逻辑里只做比对,却忘了验证完立刻 unset 或覆盖它。更隐蔽的问题是,有些代码在验证失败时没销毁,导致同一验证码可被试错多次。
- 每次调用验证码生成逻辑(比如
captcha.php)后,必须把值写入 Session 并设置过期时间:$_SESSION['captcha'] = $code; $_SESSION['captcha_expire'] = time() + 180; - 验证动作(如登录表单提交)中,先检查
time() > $_SESSION['captcha_expire'],超时直接拒绝,不比对 - 无论比对成功或失败,验证完成后必须执行
unset($_SESSION['captcha'], $_SESSION['captcha_expire']) - 不要用
session_destroy()全局清空——会干掉用户登录态等其他关键数据
为什么不能把验证码存进 Cookie 或前端 JS 变量
有人图省事,把验证码值塞进 document.cookie 或全局变量 window.captchaCode,再通过 AJAX 提交。这等于把钥匙挂在门把手上:HTTP 协议本身不加密 Cookie,中间人能直接读;JS 变量更是一看源码就暴露。攻击者根本不用 OCR,复制粘贴就能重放。
真正安全的路径只有一条:验证码值全程不出服务器,只靠 Session ID 关联。浏览器只需拿到图片和一个无意义的 token(比如图片 URL 的 query 参数 ?t=123456),后端用这个 token 查 Session 里的对应值。
- 前端请求
/captcha.php?t=<?php echo uniqid(); ?>,t参数仅用于防缓存,不参与验证逻辑 -
captcha.php内部不读取$_GET['t']做校验,只负责生成、存 Session、输出图片 - 验证接口(如
login.php)只从$_SESSION读,不接受任何来自 GET/POST 的验证码明文传输
字母混淆策略对防重放无效,但影响 OCR 破解成本
用相似字母(如 0/O、1/l/I)制造视觉混淆,本质是提高机器识别难度,跟防重放完全无关。如果验证码已被截获,混淆再多也挡不住人工抄写或一次性脚本提交。
真正该做的是控制“可使用窗口”:缩短有效期(建议 ≤ 180 秒)、限制单 IP 每分钟最多请求 3 次、验证失败 5 次后临时封禁该 Session ID 对应的验证码获取权限。
- GD 库绘图时避免使用易混淆字符集,推荐显式定义:
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';(去掉 0、1、O、I、l) - 干扰线和噪点要适度——太多影响人类识别,太少降低 OCR 成本;实测 3~5 条随机线 + 20~30 个噪点像素较平衡
- 不要依赖字体扭曲来防重放,那是防 OCR 的,不是防重放的
前后端分离场景下 Session 绑定容易失效
Vue/React 项目调用 PHP 验证码接口时,若跨域且未携带凭证,浏览器不会自动发送 Cookie,导致后端 session_start() 创建的是新会话,生成的验证码和后续验证不在同一个 Session 里——看起来“防重放”了,其实是验证永远失败。
这不是逻辑漏洞,是部署配置问题。必须确保前端请求带 credentials: 'include',后端响应头包含 Access-Control-Allow-Credentials: true 和明确的 Access-Control-Allow-Origin(不能为 *)。
- 前端 fetch 示例:
fetch('/api/captcha', { credentials: 'include' }) - PHP 接口开头加:
header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Origin: https://your-frontend-domain.com'); - 检查
session.cookie_samesite配置,生产环境建议设为Lax或Strict,避免宽松模式导致跨站请求意外携带 Cookie
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











