博客

防护 API 与表单免受滥用和垃圾信息

更新于: 12 分钟阅读
安全rate-limiting反垃圾校验apiturnstile

联系表单、登录 endpoint 和公开 API 常成为滥用目标:垃圾信息、暴力破解、抓取和自动提交。有效防护需要多层组合,单层不够。

本文介绍在 Astro、Laravel 和 Node.js 应用中保护表单与 endpoint 的分层方法——与本作品集生产环境使用的模式相同。

防护层

  1. 限流:在时间窗口内按 IP 限制请求。
  2. 蜜罐:机器人会填、用户看不见的隐藏字段。
  3. 表单计时:检测快于人类的提交(< 3.5s)。
  4. 来源检查:生产环境校验 Origin/Referer。
  5. 模式校验:服务端使用 Zod 或等价方案。
  6. 消毒:处理或存储前清理输入。
  7. 可选 CAPTCHA:流量足够时使用 Cloudflare Turnstile。

限流

应用于敏感的公开 endpoint:

  • 登录与注册:每 IP 每分钟 5 次。
  • 密码重置:每 IP 每小时 3 次。
  • 联系表单:每 IP 每分钟 5 次。
  • 未认证 API:视用例而定。

单进程可用内存实现;多副本时用 Redis。返回 429 Too Many RequestsRetry-After header。

蜜罐

用 CSS 隐藏的字段(display: noneposition: absolute; left: -9999px)。机器人会自动填写;用户看不到。若有值则静默拒绝(返回 200 但不处理,避免暴露给机器人)。

表单计时

渲染表单时记录时间戳(隐藏字段或 session)。收到 POST 时,若耗时少于 3–4 秒则拒绝。机器人瞬间提交;用户至少需要几秒阅读填写。

服务端校验

每个 API endpoint 使用 Zod(或等价)模式:

  • 严格类型:邮箱格式、电话格式、最大长度。
  • 明确必填与可选字段。
  • 拒绝含意外字段的 payload(strip 或 reject)。
  • 客户端通用错误信息;详情仅记在服务端日志。

消毒

  • 纯文本字段去除 HTML。
  • 规范化空白与控制字符。
  • 截断超长字符串。
  • 切勿将用户输入未转义地拼进 SQL 或模板。

来源检查

生产环境校验 OriginReferer header 是否匹配站点域名。拒绝未知域名请求。并非万无一失(可伪造),但能过滤基础机器人和跨域脚本。

Cloudflare Turnstile

垃圾流量足以承受额外摩擦时,Cloudflare Turnstile 轻量且注重隐私。用 TURNSTILE_SITE_KEY(公开)和 TURNSTILE_SECRET_KEY(服务端)配置。服务端在处理表单前验证 token。

endpoint 完整流程

  1. 限流检查 → 超限返回 429。
  2. 蜜罐检查 → 有值则静默 200。
  3. 表单计时 → 过快返回 400。
  4. 来源检查 → 无效来源返回 403。
  5. Turnstile 验证(若配置)→ 无效返回 400。
  6. Zod 校验 → 字段错误返回 400。
  7. 消毒 → 处理。

常见错误

  • 只依赖前端校验。
  • 只在登录限流,联系表单和 webhook 不限。
  • 蜜罐可见或可聚焦的 tabindex(读屏软件会填写)。
  • 对蜜罐返回 403(机器人会学习适应)。
  • 记录含邮箱电话的完整 payload(日志中的 PII)。
  • 三副本各用内存限流(计数器不共享)。

相关内容 安全审计网络安全REST API .

常见问题

蜜罐够防机器人吗?

不够。蜜罐能过滤基础机器人,但应配合限流、表单计时,生产环境还可加 Turnstile 等 CAPTCHA。

限流应加在哪里?

公开 endpoint:登录、注册、密码重置、联系表单、webhook 和未认证 API。按 IP,必要时按已登录用户。

在前端还是后端校验?

两者都要,但后端是必须的。前端校验改善体验;后端校验才是安全关键。

Turnstile 还是 reCAPTCHA?

Cloudflare Turnstile 轻量、注重隐私、集成顺畅。reCAPTCHA v3 可用但依赖 Google。取决于技术栈和隐私政策。

内存限流能扩展吗?

单进程可以。多副本需要 Redis 或其他共享存储。开发环境用内存即可。