导读:企业网站的留言、报名、预约表单,是业务线索的入口,也是攻击者最爱薅的对象——批量提交灌爆邮箱、刷爆短信、拖垮接口。本文从验证码、频率限制、行为风控、数据校验四条防线,给出可直接落地的表单防刷配置,每步都有代码示例。
表单被刷不是玄学,常见三类:①脚本批量提交(无头浏览器直接 POST);②短信/邮件轰炸(用你的接口给手机发验证码);③薅羊毛(用表单做自动化占座)。三者共同点是"高频、无人工痕迹"。
防护思路也是三层:第一层验证码挡脚本,第二层频率限制挡轰炸,第三层行为风控挡聪明脚本,最后一层服务端数据校验兜底。
图形验证码对 OCR 脚本基本失效,推荐滑块/点选或行为式验证码。接入要点是服务端二次校验——前端只负责展示,最终提交时服务端必须调用验证结果接口确认,否则前端可绕过:
// 前端提交示例:携带验证凭证
const resp = await fetch('/api/form/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ form: formData, captchaToken: token })
});要点:验证码的 key 要绑定会话与表单类型,防止验证码跨表单复用;验证通过后凭证一次性失效,防止重放。
验证码挡不住"真人在线批量提交"。频率限制要做两层:按 IP 限 + 按设备指纹限(浏览器指纹:UA、Canvas、时区、屏幕参数组合)。
服务端可用 Redis 做滑动窗口限流:
# 同一表单同一IP 5分钟内最多3次
SET form:limit:{ip} 1 EX 300 NX
INCR form:limit:{ip}
# 超过3次返回 429要点:IP 限制要防绕过(代理池),所以必须叠加设备指纹;限流响应要友好提示("提交过于频繁,请稍后再试"),而不是直接报错吓跑正常用户。
聪明脚本会自己点验证码。行为风控看三件事:①表单填写耗时(真人填 10 秒以上,脚本 0.5 秒);②鼠标轨迹/键盘输入事件(脚本没有真实事件);③提交前是否经过页面停留。
// 前端采集:记录填写开始时间与提交耗时
const startTs = Date.now();
form.addEventListener('submit', () => {
const costMs = Date.now() - startTs;
// costMs < 3000 视为可疑,与服务端阈值联动
});要点:行为数据只做嫌疑评分,不做一刀切拒绝——评分高的要求二次验证(再拖一次滑块),评分正常的直接放行,兼顾体验与安全。
前三道防线都绕过时,服务端校验是最后底线:①必填字段长度与格式校验;②手机号/邮箱格式正则;③内容相似度去重(同一内容 1 小时内重复提交直接丢弃)。
-- 内容指纹去重:对提交内容做哈希,短时间重复直接拦截
SELECT COUNT(*) FROM form_log
WHERE fingerprint = ? AND created_at > NOW() - INTERVAL 1 HOUR;表单防刷要按「验证码 → 限流 → 行为风控 → 服务端校验」四层纵深设计,每层独立开关、独立告警,先上线限流与校验兜底,再逐步开启验证码与风控,避免误伤正常业务。同类分层在乔拓云企业网站的表单模块中有对应实现,中小网站可直接参照该模块的限流与校验策略起步。
表单防刷没有银弹,靠的是四层纵深:验证码挡脚本、限流挡轰炸、风控挡聪明脚本、校验挡脏数据。每层独立可开关、可验证,先兜底后加固,就能在体验与安全之间找到平衡点。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。