最可靠的方式是前端生成仅用于显示的算术题(如“7+3”),后端必须重新计算验证;运算符限于+、-,操作数为1–10整数,避免无效式子;所有校验须服务端执行,配合session/ip限流与过期机制防刷。

直接用 JavaScript 生成并验证算术验证码最可靠,服务端不参与运算逻辑时容易被绕过——必须在后端重新计算一次。
怎么用 Math.random() 生成带运算符的算术题
前端生成题目只是为了显示,不能用来验证。但得让它看起来“像人出的”:避免 0 - 5 或 2 / 0 这种无效式子。
- 只用
+和-最稳妥,避免除零、小数、负数结果带来的校验歧义 - 两个操作数都限定在
1–10范围内,用Math.floor(Math.random() * 10) + 1 - 运算符随机选:
['+', '-'][Math.floor(Math.random() * 2)] - 把完整表达式(如
"7+3")存进隐藏<input type="hidden">,同时把答案写进data-answer属性备用
为什么不能只靠前端验证 input.value === answer
用户打开 DevTools 两秒就能改掉 data-answer 或直接绕过判断逻辑。常见错误是只在 JS 里比对,然后放行表单提交。
- 所有验证码校验必须走服务端,哪怕只是简单复算一遍字符串
- 后端收到
captcha_expr=4+9和captcha_input=13后,要自己eval()(Node.js)或ast.literal_eval()(Python)解析表达式,再比对结果 - 注意:PHP 用
eval()前必须严格白名单过滤字符,推荐用bcadd()/bcsub()拆解处理 - 别把原始表达式直接拼进 SQL 或日志,防止注入或泄露
怎么防止用户反复试错?关键看 session 和 IP 限流
验证码不是防破解的终极手段,而是增加自动化攻击成本。没限制的验证码等于没设防。
- 每次生成新题,就往
session存一次captcha_answer和captcha_expired_at(比如 5 分钟后) - 验证前先检查是否超时、是否已被使用(验证成功后立即清空
session中的该字段) - 同一 IP 在 1 分钟内连续失败 5 次,返回
429 Too Many Requests,并暂停发放新验证码 10 分钟 - 别依赖前端传来的
captcha_id做唯一标识——它可能被重放,要用服务端生成的 token 绑定 session
真正难的不是生成“3+5=?”,而是让这个“?”在传输、存储、验证全链路中不被污染、不被跳过、不被批量刷穿。后端那行复算代码,比前端画十个动画还关键。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











