跳到主要内容
IM智引科技

研究 / 外贸与 B2B 增长

网站安全维护:防垃圾表单与定期巡检清单

静态站的攻击面比动态站小得多,但表单、依赖包和第三方服务仍是风险点。这篇给出防垃圾表单的三层方案(无需 reCAPTCHA)、依赖更新策略,以及一份可以直接照着执行的月度/季度巡检清单。

BLKTECH 编辑部2026年8月4日11 分钟难度 入门免费CloudflareTurnstilenpm

防垃圾表单三层:Honeypot 隐藏字段(拦截简单机器人)+ 提交时间检测(少于3秒判定为机器人)+ Cloudflare Turnstile(免费且无需用户交互,替代 reCAPTCHA)。定期维护:每月检查依赖漏洞和证书状态,每季度检查认证有效期和第三方服务配额。

网站安全维护:防垃圾表单与定期巡检清单

静态站的攻击面

第 14 篇选了 Astro + CF Pages 的静态方案,这个选择本身就消除了大部分安全风险:

静态站没有的风险:
✅ 无数据库 → 无 SQL 注入
✅ 无服务端代码执行 → 无 RCE
✅ 无后台登录 → 无凭证爆破
✅ 无 PHP/WordPress → 无插件漏洞(外贸站被黑的最常见原因)

剩下的风险点只有四个:

风险点 影响 优先级
表单垃圾提交 淹没真实询盘,浪费 API 配额
依赖包漏洞 供应链风险(构建时注入)
API 密钥泄露 第三方服务被滥用
第三方服务配额耗尽 表单失效,询盘丢失

一、防垃圾表单:三层方案

层 1:Honeypot 隐藏字段(拦截 60–70%)

第 19 篇已经加了,这里补充正确的实现细节。

<!-- 正确的 honeypot 实现 -->
<div class="hp-field" aria-hidden="true">
  <label for="website-url">Website</label>
  <input
    type="text"
    id="website-url"
    name="website_url"
    tabindex="-1"
    autocomplete="off"
  >
</div>

<style>
/* 用绝对定位移出视口,而不是 display:none */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
</style>

为什么不用 display: none:较新的爬虫会检查 CSS,跳过 display:none 的字段。绝对定位移出视口的方式对机器人来说仍然“可见”。

三个关键属性

  • tabindex="-1":键盘用户 Tab 不会聚焦到它
  • aria-hidden="true":屏幕阅读器忽略它(可访问性)
  • autocomplete="off":浏览器不会自动填充

字段名要选机器人爱填的(websiteurlphone2),不要用 honeypot 这种明显的名字。

层 2:提交时间检测(拦截 20–30%)

人类填完一个 5 字段表单最少需要 8–15 秒。机器人通常在 1–2 秒内提交。

// 表单加载时记录时间戳
const formLoadTime = Date.now();

form.addEventListener('submit', async (e) => {
  e.preventDefault();

  const elapsed = (Date.now() - formLoadTime) / 1000;
  const formData = new FormData(form);
  const payload = Object.fromEntries(formData);

  payload._elapsed = elapsed;   // 传给后端判断

  // 客户端也做一次拦截(减少无效请求)
  if (elapsed < 3) {
    // 静默"成功",不提示机器人被拦截了
    showSuccessMessage();
    return;
  }

  await fetch(N8N_WEBHOOK, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
  showSuccessMessage();
});

在 n8n 的过滤节点(第 58 篇)里加上这个判断:

// 补充到第 58 篇的垃圾过滤 Function 节点
if (data._elapsed != null && data._elapsed < 3) {
  isSpam = true;
  spamReason = `submitted_too_fast: ${data._elapsed}s`;
}

注意:不要在前端提示“你提交太快了”。静默处理,让机器人以为成功了——否则它会调整策略重试。

层 3:Cloudflare Turnstile(拦截剩余的)

如果前两层还不够(垃圾提交仍然很多),加 Turnstile。它是 Cloudflare 的免费 CAPTCHA 替代方案。

为什么用 Turnstile 而不是 reCAPTCHA

Turnstile reCAPTCHA v2
用户交互 通常无需交互(自动通过) 需要点击/选图
隐私 不追踪用户 Google 追踪(GDPR 需额外声明)
成本 免费无限 免费有限额
中国访问 正常 常被墙(关键差异)

中国访问这一条对外贸站是决定性的——如果你的团队在国内测试表单,reCAPTCHA 加载失败会导致表单完全不可用。

配置

<!-- 1. 加载 Turnstile 脚本 -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

<!-- 2. 在表单里加 widget -->
<div
  class="cf-turnstile"
  data-sitekey="YOUR_SITE_KEY"
  data-theme="light"
  data-size="flexible"
></div>

在 n8n 里验证 token:

// n8n HTTP Request 节点:验证 Turnstile token
// POST https://challenges.cloudflare.com/turnstile/v0/siteverify
{
  "secret": "{{ $env.TURNSTILE_SECRET }}",
  "response": "{{ $json['cf-turnstile-response'] }}",
  "remoteip": "{{ $json._clientIp }}"
}

// 后续 Function 节点判断
const verify = $input.item.json;
if (!verify.success) {
  return { json: { ...data, isSpam: true, spamReason: 'turnstile_failed' } };
}

建议的启用顺序:先只用层 1 + 层 2,观察一个月。如果垃圾提交少于每周 2–3 条,不需要加 Turnstile——少一个第三方脚本对性能和可用性都更好。


二、依赖包安全

静态站的依赖漏洞不会直接影响线上(构建产物是纯 HTML/CSS/JS),但存在构建时的供应链风险。

每月检查

# 检查已知漏洞
npm audit

# 只看高危和严重
npm audit --audit-level=high

# 查看可更新的包
npm outdated

更新策略

补丁版本(1.2.3 → 1.2.4):直接更新
  npm update

次版本(1.2.x → 1.3.0):更新后跑构建验证
  npm install package@^1.3.0
  npm run build

主版本(1.x → 2.0):读 CHANGELOG,评估破坏性变更后再决定
  → 静态站不急于升级主版本,能构建成功就不动

Astro 的特殊说明:Astro 主版本升级通常涉及配置变更。升级前先在分支上做,用 CF Pages 的 Preview Deployment(第 22 篇)验证,确认无问题再合并。

自动化:GitHub Dependabot

在仓库根目录加 .github/dependabot.yml

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "monthly"
    open-pull-requests-limit: 5
    # 只自动提补丁和次版本的 PR,主版本手动处理
    ignore:
      - dependency-name: "*"
        update-types: ["version-update:semver-major"]

Dependabot 会自动提 PR,CF Pages 会为每个 PR 生成预览部署——你只需要看预览没问题就合并。


三、API 密钥管理

外贸站会用到几个 API 密钥(Resend、Turnstile Secret、Anthropic API Key 等)。

绝对不能做的

❌ 把密钥写在前端代码里(任何人都能在浏览器看到)
❌ 把密钥提交到 Git(即使后来删除,历史记录里仍然存在)
❌ 把 .env 文件提交到仓库

正确做法

# .gitignore 必须包含
.env
.env.local
.env.production
.dev.vars        # Cloudflare Workers 本地变量文件

密钥存放位置:

用途 存放位置
CF Pages 构建时变量 Pages → Settings → Environment variables
CF Workers 运行时密钥 wrangler secret put KEY_NAME
n8n 中的密钥 n8n Credentials 管理(加密存储)
本地开发 .env 文件(已 gitignore)

如果密钥泄露了

1. 立刻在服务商控制台吊销该密钥(不是先改代码)
2. 生成新密钥,更新到环境变量
3. 检查服务商的用量记录,确认是否被滥用
4. 如果密钥曾提交到 Git 历史:
   - 公开仓库:必须吊销,历史无法真正清除
   - 私有仓库:吊销后可选择重写历史(git filter-repo)

GitHub 的 Secret Scanning(公开仓库自动启用)会检测常见的密钥格式并通知你。私有仓库需要 GitHub Advanced Security 才有这个功能。


四、第三方服务配额监控

这是最容易被忽略但影响最直接的一项——配额耗尽时表单会静默失效,你收不到任何询盘也不会收到报错

需要监控的配额

服务 免费额度 耗尽后果 检查频率
Resend 100 封/天,3000 封/月 询盘通知和自动回复都发不出 每月
Formspree(如用) 50 次提交/月 表单提交失败 每月
n8n Cloud(如用) 5000 次执行/月 流程停止 每月
CF Workers 100,000 请求/天 表单处理失败 一般不会超
Brevo(第 12 篇) 300 封/天 邮件发不出 每月
Anthropic API 按量付费 批量生成中断 用量大时每周

配额告警配置

Resend 和 Brevo 都支持用量告警,在控制台设置:

建议阈值:达到免费额度的 70% 时发邮件提醒
理由:70% 时还有足够时间处理(升级套餐或排查异常用量)

异常用量排查:如果某天用量突然翻倍,通常是垃圾表单被自动回复触发了大量邮件。这时应该:

  1. 检查 Notion 里 Grade=SPAM 的记录数(第 58 篇)
  2. 在 n8n 流程里确认自动回复节点在垃圾过滤之后(不要给垃圾提交发自动回复)

五、月度巡检清单

每月花 20 分钟,照着做:

□ 依赖安全
  npm audit --audit-level=high  → 无高危漏洞
  合并 Dependabot 的补丁级 PR

□ 站点可用性
  UptimeRobot 上月可用率 ≥ 99.9%(第 26 篇)
  如有宕机记录,确认原因已排除

□ 表单功能(最重要,必须实测)
  提交一条测试询盘 → 确认:
  □ 收到通知邮件
  □ 买家收到自动回复
  □ Notion 数据库有新记录(如用第 58 篇的流程)

□ 第三方服务配额
  Resend / Brevo 用量 < 70%
  n8n 执行次数 < 70%(如用 Cloud 版)

□ 垃圾提交量
  查看 Notion 中 Grade=SPAM 的上月数量
  > 每周 5 条 → 考虑启用 Turnstile

□ 证书与 DNS
  访问站点确认 HTTPS 正常(🔒 图标)
  Cloudflare SSL 状态为 Active

表单实测这一项不能省。第三方服务变更、API 密钥过期、n8n 流程失效——这些都不会主动报错,只有实测能发现。见过太多站点表单坏了两个月才发现。


六、季度巡检清单

每季度额外检查这些(配合第 50 篇的健康度报告一起做):

□ 认证证书有效期
  ISO 9001 / CE / ATEX 等是否临近到期
  → 到期前 3 个月启动复审流程
  → 网站上的证书信息同步更新(第 57 篇)

□ 内容准确性抽查
  随机抽 5 个页面,核对:
  □ 参数表数据与最新规格书一致
  □ 认证信息与实际持有的证书一致
  □ 引用的行业标准编号无误(第 42 篇强调过 AI 会编造标准号)
  □ 停产型号页面已标记 deprecated(第 03 篇)

□ 安全响应头
  用 securityheaders.com 复查评分 ≥ B(第 23 篇)
  (CF 或框架升级后配置可能变化)

□ AI 爬虫可访问性
  curl -A "GPTBot" https://yourdomain.com/products/xxx/ | head -50
  → 确认返回正常 HTML 内容(第 43 篇)
  → robots.txt 未意外屏蔽 AI 爬虫

□ 备份确认
  Git 仓库有远程备份(GitHub 本身即备份)
  registry.json / entities.yaml 已提交到仓库
  Notion 数据库导出一份 CSV 存档(询盘数据)

registry.json 和 entities.yaml 必须在 Git 里——它们是整个 SEO 体系的事实来源(第 01、55 篇),丢了要重建的成本极高。


七、事故响应预案

写一份简单的应急流程,存在容易找到的地方。

## 网站无法访问

1. 检查 CF Pages → Deployments,最近一次部署是否失败
   → 失败:查看构建日志,回滚到上一个成功版本
     (CF Pages 支持一键 Rollback)
2. 检查 Cloudflare → DNS,记录是否正常
3. 检查域名是否过期(Cloudflare Registrar → Domains)
4. 用 downforeveryoneorjustme.com 确认是全站问题还是本地网络

## 询盘表单失效

1. 提交测试询盘,看浏览器 Console 有无报错
2. 检查 n8n 流程执行历史,是否有失败记录
3. 检查 Resend / Brevo 配额是否耗尽
4. 检查 API 密钥是否过期或被吊销
5. 临时方案:在页面顶部加公告,展示直接邮箱和 WhatsApp

## 收到大量垃圾提交

1. 确认 Honeypot 和时间检测是否生效(看 n8n 的 spamReason 分布)
2. 启用 Cloudflare Turnstile
3. 如仍严重:Cloudflare → Security → WAF 加速率限制规则
   (同一 IP 每 10 分钟最多 3 次表单提交)

→ 外链建设基础:适合小团队的白帽增长策略

NEXT ACTION / 下一步

继续系列:AI 外贸站建设全系列

把读到的方法变成一个小行动,完成后再回来迭代。

继续

RELATED / 相关推荐

接着读这些

按同一分类、系列与标签为你挑选。