必须用 random_int() 生成验证码:预先定义剔除易混淆字符(如0、o、i、l)的32字符集,循环调用 random_int() 取索引拼接;服务端绑定 session 存储并限时5分钟,校验后立即销毁。

如何用 random_int() 生成安全的字母数字混合验证码
直接用 rand() 或 mt_rand() 生成验证码存在可预测风险,PHP 7+ 必须优先用 random_int() —— 它是密码学安全的整数生成器,能防暴力穷举和会话劫持。
常见错误是拼接大小写字母 + 数字字符串后用 substr(str_shuffle($chars), 0, $len),但 str_shuffle() 不依赖安全随机源,且 PHP 8.2+ 已标记为“不推荐”。
- 正确做法:预先定义字符集(如
'23456789ABCDEFGHJKLMNPQRSTUVWXYZ',主动剔除易混淆字符O、0、I、l) - 循环
$length次,每次调用random_int(0, strlen($chars) - 1)取索引 - 避免用
array_rand()—— 它内部不保证使用加密安全 RNG
验证码字符串里为什么避开 O、0、I、l
不是为了“美观”,而是降低用户输入错误率。实测数据显示,含 0 和 O 的 4 位验证码人工识别错误率超 12%,尤其在小字号、低对比度或移动端截图场景下。
推荐字符集(32 个字符,兼顾安全性与可读性):'23456789ABCDEFGHJKLMNPQRSTUVWXYZ' —— 去掉 0、1、O、I、Q、Z 等易混字符。
-
1和l在等宽字体中几乎无法区分 -
Q和0在部分验证码字体中形状接近 - 长度建议设为 4~6 位:太短易爆破,太长用户不愿输
生成后怎么存、怎么校验才不被绕过
验证码值不能只存在前端(比如藏在 hidden input 或 JS 变量里),必须服务端绑定 session 或临时 token 存储,并设置超时(通常 300 秒)。
典型错误:校验时只比对字符串,忽略大小写或空格;或未清空已使用过的验证码,导致重放攻击。
- 存储用
$_SESSION['captcha_code'] = $code,并记录时间戳$_SESSION['captcha_time'] = time() - 校验前先检查
time() - $_SESSION['captcha_time'] > 300,超时则拒绝并清空 session - 校验时统一转小写(
strtolower())再比对,避免大小写敏感问题 - 校验成功后立即
unset($_SESSION['captcha_code'], $_SESSION['captcha_time'])
要不要加干扰线/扭曲?实际效果很有限
加简单干扰线(非密集噪点)对 OCR 识别率影响微乎其微,反而可能让视障用户或高龄用户更难识别。现代 OCR(如 Tesseract 4+)对清晰字体+适度干扰的识别准确率仍超 95%。
真正有效的防护是:限制单位 IP 的请求频率(如 5 次/分钟)、验证码使用一次即失效、配合前端简单行为检测(如鼠标移动轨迹、JS 时间戳)。
如果坚持加干扰,只用 imageline() 画 2~3 条浅灰斜线,别用 imagefilledarc() 或密集 imagesetpixel() —— 这类操作在共享主机上容易触发 CPU 限频,导致接口超时。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











