如何做一个简单的html表单验证码

7次阅读

浏览器端生成验证码无安全意义,必须服务端生成并比对;推荐session存随机字符串、前端data属性显示、提交时服务端严格校验并立即清除。

如何做一个简单的html表单验证码

为什么不用 JavaScript 生成验证码图片

浏览器端生成的图片验证码(比如用 canvas 绘制)毫无安全意义——源码全在前端,机器人直接读像素或绕过校验就行。真要防自动化提交,必须服务端参与生成和比对。

简单表单验证码的核心不是“看起来像验证码”,而是“提交时能和服务端存的值对上”。所以优先走服务端 session + 纯文本方案,够用、轻量、不依赖图像库。

  • 后端生成随机字符串(如 4~6 位字母+数字),存进 session 或内存缓存(如 redis),键为用户会话 ID
  • 前端显示该字符串(可加简单干扰线 CSS,但非必需)
  • 表单提交时,把用户输入的值和 session 中存的原始值比对
  • 比对完立即清空该 session 键,防止重放

html 表单里怎么嵌入动态验证码文本

不能写死 <input type="text" value="AB3X">,得让后端吐出真实值。最简做法:后端渲染 HTML 时,把验证码明文塞进一个带 data-* 属性的容器里,再用 js 读出来显示——既避免裸露在 dom 文本中被爬虫扫到,又不用额外接口

示例(假设后端模板语法是 Jinja2 / EJS 类):

立即学习前端免费学习笔记(深入)”;

<div id="captcha-display" data-value="{{ captcha_text }}"></div> <input type="text" name="captcha" required>

对应前端 JS(无需框架):

const el = document.getElementById('captcha-display'); if (el) {   el.textContent = el.dataset.value || ''; }
  • 不要把 captcha_text 放在 <input value="..."> 里——容易被自动填充插件覆盖
  • 不要用 innerHTML 渲染,避免 xsstextContent 更安全
  • 如果服务端没传 data-value,前端留空或显示“加载失败”,别 fallback 到固定字符串

提交时如何验证用户输入是否匹配

关键不在前端校验(那只是体验优化),而在于后端收到 POST 请求后,立刻查当前会话对应的验证码值,并严格比对(区分大小写、去首尾空格)。

常见错误:

  • 前端 JS 校验通过就放行——完全无效,绕过 JS 一抓一个准
  • 后端比对用 == 而非 ===,导致 "0000"0 意外相等
  • 没清空 session.captcha,导致同一验证码可重复使用多次
  • 没设超时(比如 5 分钟),旧验证码长期有效,增大撞库风险

推荐后端逻辑(伪代码):

if (!session.captcha || Date.now() - session.captcha.ts > 5 * 60 * 1000) {   return error("验证码已过期"); } if (userInput.trim() !== session.captcha.text) {   return error("验证码错误"); } delete session.captcha; // 必须删

要不要加倒计时刷新按钮

要,但别用复杂轮询。用户看不清时,点一下刷新,后端重新生成并返回新值 + 新 session 键,前端只更新 data-value 和显示文本即可。

实现要点:

  • 刷新按钮绑定 fetch("/captcha/refresh"),返回 json{"text": "K9mP"}
  • 成功后更新 data-valuetextContent,不重载页面
  • 按钮禁用 1 秒防连点,避免并发请求污染 session
  • 别在前端记倒计时——时间以服务端为准,否则时钟不同步会导致提前失效

真正难处理的是并发刷新 + 提交竞争:用户狂点刷新,又立刻提交,可能拿着旧值去比对。解决办法只有一个——每次刷新都生成新 key,提交时校验必须用本次刷新生成的那个值,而不是“最新一次”的值。

text=ZqhQzanResources