验证码安全必须配置 expire(建议90–150秒)和自定义key(≥16位、禁用常见词),启用usenoise、usecurve及fontsize=25防ocr,弃用session改用key+缓存校验,并绑定ip/设备标识、一次有效、限频防刷。

captcha.php 必须显式配置 expire 和 key
默认 180 秒过期 + 默认密钥,等于把验证码的“锁芯”直接暴露。攻击者只要抓到一次 session,就能反复重放校验请求。
在 config/captcha.php 中必须写死两项:
-
'expire' => 120(建议 90–150 秒,太短伤体验,太长增风险) -
'key' => 'your_custom_secret_string_here'(长度 ≥16,禁用项目名、日期、常见单词)
注意:key 一旦设好就不能改——否则所有已生成但未提交的验证码立即失效。上线前定好,别等出问题再调。
useNoise 和 useCurve 是防 OCR 的最低门槛
默认验证码图太干净,tesseract 之类工具几行命令就能识别。不加干扰,等于没设防。
这两项不是“可选”,是必须启用的基础项:
-
'useNoise' => true(噪点破坏字符连通性) -
'useCurve' => true(曲线干扰轮廓,大幅降低 OCR 准确率) -
'fontSize' => 25(25–30px 最佳;太小模糊,太大留白多、特征明显)
别开 useImgBg:自定义背景图若纹理规则或对比度低,反而成 OCR 定位锚点。
前后端分离时,千万别依赖 session_id 校验
跨域、反向代理、微服务场景下,captcha_check() 恒为 false,基本可以断定是 session 上下文断裂——不是你代码错,是机制不匹配。
正确做法是弃用 session,改用 key + 缓存:
- 后端生成接口返回
{ "key": "cap_xxx", "img": "data:image/png;base64,..." } - 前端把
key存进表单字段,和用户输入的code一起提交 - 登录接口调用
Captcha::check($code, $key),校验完立刻cache($key, null)或$redis->del("captcha:$key")
这个模式不依赖 cookie,适配 Nginx 网关、多实例部署、小程序等真实环境。
验证码必须一次有效,且绑定上下文
校验通过后不清除缓存,等于给攻击者留后门;不绑定 IP 或设备标识,key 就能被复用到其他账号。
实操要点:
- 每次
check()成功后,必须立即删掉缓存键,不能等过期 - 生成 key 时拼入上下文,比如
"captcha_{$ip}_{$uuid}"或"captcha_{$phone}_{$ua_hash}" - 对同一 IP,1 分钟内最多请求 3 次验证码,超限直接返回 429,不返回图片也不提示错误
最易被忽略的是“上下文绑定”——很多项目只做了 key 生成和清除,却忘了限制 key 的使用范围,导致一个验证码能在多个设备、多个账号间流转。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











