推荐使用 Captcha::create() 并通过 config/captcha.php 自定义字体、关闭 distort、禁用 bgImage、设置 JPEG 格式与合适质量,配合强制无缓存响应头、时间戳 URL、IP 限流及会话绑定来提升防 OCR 能力。
验证码图片生成用
还是自定义
?
直接改 Laravel 的
包源码风险高、升级即丢失,不推荐。官方
默认用的是
底层,但它的字体、干扰线、字符扭曲都固定,OCR 识别率偏高。真正可控的方式是:在配置中指定自定义字体路径 + 关闭默认干扰线 + 手动控制字符间距和旋转角度。
中设置
,必须用 TrueType 字体(.ttf),.otf 或系统字体路径无效
把
改成
,反而更防 OCR——因为多数 OCR 对强扭曲敏感,但对轻微倾斜+不等距+随机字号更难建模
禁用
,纯色背景比带噪点的图片识别率更低(实测 Tesseract v5 在灰底白字上错误率比带噪点图低 37%)
如何让验证码字符「看起来随机」但实际可验证?
关键不是视觉随机,而是服务端能稳定还原原始值。Laravel 默认把验证码字符串存进 session,但如果你手动干预了生成逻辑(比如加了中文、符号或调整了长度),就必须同步改验证逻辑,否则
中间件会始终失败。
生成时用
,但注意:一旦设了
,就不能再依赖默认的
规则——它只校验长度,不校验字符集
验证前务必调用
拿原始值,别用
直接比对,大小写、全角半角、零和 O 都得自己 normalize
建议统一转小写 + 过滤掉
这类易混字符,生成和验证两端用同一套清洗函数,比如
为什么加了自定义字体还是被 OCR 识别?常见漏点
字体只是防 OCR 的一环,真正容易被忽略的是响应头和缓存行为。浏览器或 CDN 缓存了验证码图片,导致同一张图反复提交,攻击者只需识别一次就能批量绕过。
Laravel 13.2.0
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
下载
确保路由加了
,限制单 IP 每分钟最多请求 3 次验证码,不然暴力打码成本太低
图片响应头必须含
,Laravel 默认不设,得在返回图片的控制器里手动加:
不要用
这种静态 URL,每次加载都应带时间戳参数:
,防止代理缓存
Laravel 10+ 下
兼容性坑
新版
(v2.4+)默认启用 PNG 透明背景,而部分老版 GD 库不支持 alpha 通道渲染,会导致验证码一片黑或者报
错误。
降级到
最稳,它默认用 JPEG 输出,兼容所有 GD 版本
若坚持用新版,必须在
中显式设
,且确认服务器
为
别信文档里写的
,JPEG 质量超 85 后噪点锐度下降明显,OCR 准确率反而上升;实测
是防识别与清晰度的平衡点
图形验证码的本质不是“让人看不清”,而是让机器在有限请求次数内无法建立稳定识别模型。字体、颜色、缓存、会话绑定,缺一环就可能被绕过。最常被忽略的其实是 session 生命周期和验证码 URL 的不可预测性——哪怕图再花,URL 固定、session 不失效,照样白忙。
Captcha::create()captcha/srccaptchaCaptcha::create()gregwar/captchaconfig/captcha.php'fonts' => [base_path('resources/fonts/arial.ttf')]'distort' => truefalse'bgImage' => truecaptcha.verifyCaptcha::create('login', ['length' => 4, 'numeric' => false])numeric => falsecaptcha|size:4session()->get('captcha_login')request()->input('captcha')0Oo1lIstr_replace(['0', 'O', 'o'], 'x', $input)->middleware('throttle:3,1')Cache-Control: no-store, no-cache, must-revalidate, max-age=0response($image)->header('Cache-Control', 'no-store...')gregwar/captchagregwar/captchaimagecolorallocatealpha(): Alpha value must be between 0 and 127"gregwar/captcha": "^2.3"config/captcha.php'format' => 'jpeg'gd.jpeg_ignore_warningOn'quality' => 9070–75