应使用 random_int(100000, 999999) 生成安全六位验证码,确保无前导零、密码学安全;需存入 session 并设过期时间,校验时用严格比较并及时销毁,配合限流与模糊错误提示防爆破。

用 random_int() 生成安全的六位数字验证码
直接用 rand() 或 mt_rand() 生成六位数验证码存在安全风险——它们不是密码学安全的随机源,可能被预测。生产环境必须用 random_int()。
六位数范围是 100000 到 999999(不能以 0 开头,否则实际变成五位或更少):
echo random_int(100000, 999999);
- 别写成
random_int(0, 999999):会生成带前导零的数字(如7234),转字符串后长度不足六位 - 也别用
sprintf('%06d', ...)补零:补出来的不是真随机分布,且掩盖了范围错误 - 如果需要存入 session 或返回 JSON,保持整型即可;前端显示或短信发送时再转字符串,无需额外处理
验证码要进 session?记得先启动 session_start()
生成后不存、不校验,验证码就等于没用。常见漏掉的是 session 初始化:
session_start(); $_SESSION['captcha'] = random_int(100000, 999999);
- 必须在任何输出(包括空格、BOM、
<?php前空白)之前调用session_start(),否则报错Cannot send session cache limiter - 不要把验证码直接塞进 cookie(
setcookie()):易被篡改,且无服务端绑定,完全失效 - 建议加个过期时间标记:
$_SESSION['captcha_time'] = time();,后续校验时比对是否超时(比如 5 分钟)
校验时注意类型和时效性
用户提交的验证码通常是字符串(表单输入),而 random_int() 返回整型,但 PHP 松散比较(==)会自动转换,看似能过——但隐患大:
- 攻击者提交
"000123"可能绕过(如果服务端用了==且原始值是123)——但这里我们强制生成 100000–999999,所以不会出现前导零问题;不过仍推荐用严格比较===+ 类型统一 - 正确做法:
if ((int)$_POST['captcha'] === $_SESSION['captcha'] && time() - ($_SESSION['captcha_time'] ?? 0) - 校验通过后,立刻 unset:
unset($_SESSION['captcha'], $_SESSION['captcha_time']);,防止重放
不用图形验证码?纯数字也要防暴力
六位纯数字共 90 万种组合,看起来难爆破,但实际中攻击者每秒可试几十次——1 小时就能扫完全部。光靠“六位”不够:
- 必须配合 IP + 用户标识(如登录账号)限流,例如:同一 IP 5 分钟内最多尝试 5 次
- 失败 3 次后,可临时要求输入更长验证码(如 8 位),或加入简单运算题(“3+7=”)
- 别把错误提示写成“验证码错误”和“用户名错误”分开——这会帮攻击者枚举有效账号
真正难的不是生成六位数,而是让这个数字在传输、存储、校验全链路里不被绕过、不被复用、不被预测。每个环节松一点,前面的安全生成就白做了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











