先明确一个核心事实:**HTML 本身根本不具备验证码的运行能力,更谈不上人机识别。** 这不是什么配置失误,而是从根本上就搞错了方向。
所谓“HTML验证码”,实际上是把服务端生成的验证逻辑,比如 reCAPTCHA、极验、阿里云滑动验证这类东西,通过 HTML 页面展示出来。但请记住,**校验动作必须发生在后端**。纯前端用 `
![]()
` 标签加载一张静态图片,或者用 Canvas 随手画几个扭曲的文字,那在爬虫眼里就是透明的——别说防机器了,连基本的防重放都做不到。
为什么写在 HTML 标签里的图片,根本顶不住攻击
常见的翻车现场是这样的:页面上放个 `

`,用户输入,前端直接比对字符串。结果呢?爬虫绕过 Ja vaScript、伪造请求、批量爆破,简直如入无人之境。
随便列几条致命缺陷:
- **没有会话绑定**:那张 `captcha.png` 跟用户的 session 没半点关系,同一张图可以被无限拿来回放。
- **没有随机性**:如果图片路径固定,或者参数可控,比如 `/captchan=123`,攻击者完全可以预生成所有可能的输出。
- **没有服务端校验**:前端写个 `if (input === 'abc') { submit() }`?这是教科书级别的漏洞。Ja vaScript 可以被禁用,也可以被绕过。
- **没有行为采集**:现代人机识别靠的是鼠标轨迹、触屏压力、页面停留时长这些动作特征。纯 HTML?零采集能力。
说白了,这就是一群攻不破的纸老虎。
不管是 reCAPTCHA 还是国产 SDK,后端不接,等于白搭
拿 Google reCAPTCHA 来说。`grecaptcha.execute()` 返回的 `token`,只是个临时凭证。它的唯一作用,就是传给后端,让后端去调用 `https://www.google.com/recaptcha/api/siteverify` 这个接口,拿着私钥去校验真伪。
前端的职责到此为止:**只负责触发和传递,不参与任何判断。**
几个要点必须清楚:
- **公钥(sitekey)**:放在 HTML 的 `data-sitekey` 里,或者写在 Ja vaScript 初始化中。公开也无妨,它就是个门牌号。
- **私钥(secret)**:打死也不能出现在前端代码、HTML 注释、甚至浏览器控制台里。这是底线。
- **reCAPTCHA v3**:它虽然不显示 UI,但返回的 `score` 值,必须交给后端结合业务阈值去决策。比如 `score < 0.5`,那就让用户补一个二次验证。
- **国产 SDK(极验、阿里云滑动验证)**:道理完全一样。`validate` 结果是个 Base64 字符串,必须 POST 到服务端的 SDK 接口,解密之后再做风控判定。
蜜罐字段:纯 HTML 能干的“轻量人机过滤”
严格来说它不算验证码,但确实是唯一能纯靠 HTML 实现、而且不引入第三方 SDK 的轻量方案。适合用在联系表单、订阅入口这些低风险场景。
做法很简单:
- 在表单里藏一个输入框,比如 `
`。
- 正常用户看不见这个框,自然不会填;但多数自动提交脚本会傻乎乎地遍历所有 `input`,顺手把值填进去。
- 后端收请求时检查这个字段:非空?那基本是机器人,直接拒掉。
有几条实操经验:
- **别用 `type="hidden"`**:不少爬虫会跳过 hidden 字段。要用 `style="display:none"` 或 `visibility:hidden`。
- **字段名别太直白**:用 `email`、`url` 这种常见名字,很容易被识破。换个迷惑性强点的,比如 `company_fax`、`user_agent_hint`。
---
总结一句话:**真正卡住人的,从来不是“怎么把验证码加到页面上”,而是“谁来校验、校验什么、校验之后怎么响应”。** 前端只负责呈现和传递,所有判断逻辑、行为分析、风险评分、会话状态管理,统统压在后端。把这个环节漏掉,再炫的滑块动画、AI 图形、语音验证,都是纸糊的门。