DNS, Email & Deliverability

为什么联系表单是你最大的垃圾邮件隐患

大多数联系表单都被配置为直接根据用户输入发送邮件。这使它们极易被利用。

The Wux Webtools Team The Wux Webtools Team 8 分钟阅读 人工智能辅助,人工审核
Abstract illustration of a contact form with warning symbols representing spam vulnerability
目录
  1. 问题比你想象的更早出现
  2. 联系表单为什么如此容易被利用
  3. 发送联系表单邮件的正确方式
  4. 速率限制不是可选项
  5. CAPTCHA 是权衡,不是解决方案
  6. 何时使用第三方表单服务
  7. DMARC 问题
  8. 那么 [Cookie 同意与表单跟踪](/zh-CN/blog/2026-05-02-what-changed-for-cookies-in-2026-and-what-to-do-about-it) 呢?
  9. 关键要点
  10. FAQ
  11. Sources

问题比你想象的更早出现

自 2000 年代初以来,联系表单一直是垃圾邮件的传播途径;但随着邮件服务商收紧身份验证要求,这个问题变得更严重。大多数联系表单仍然以同样的方式构建:用户填写表单,你的服务器在 From 头中使用用户的地址发送一封邮件,然后你等待回复。

这是典型的邮件伪造漏洞。垃圾邮件发送者可以利用你的表单发送看起来来自任意地址的邮件,并通过你服务器的 IP 路由出去。如果有足够多的垃圾邮件以这种方式发出,你的域名会被标记,你的合法事务邮件也将无法送达收件箱。

修复方法很直接,但大多数教程仍然做错了。

联系表单为什么如此容易被利用

一个典型的联系表单接受三个字段:姓名、邮箱和消息。服务器端处理程序会取出该邮箱地址,并直接放入一封外发 SMTP 邮件的 From 头中。这样回复很方便——你只需在收件箱里点击“回复”——但这也等于给了垃圾邮件发送者一份礼物。

当垃圾邮件发送者发现你的表单时,会发生以下情况:

  1. 他们在“from”字段中填入受害者的邮箱地址并提交表单
  2. 你的服务器照常发送一封邮件,并在 From 头中使用该受害者的地址
  3. 受害者的邮件服务器看到一封声称来自其域名、但源自你 IP 的邮件
  4. 如果你的域名缺少正确的 SPF/DKIM/DMARC 记录(即使有记录也一样),邮件仍可能送达,因为许多服务器对联系表单流量较为宽松
  5. 受害者收到一封看起来来自自己地址的垃圾邮件,或者你的域名因伪造行为被标记

这不是理论攻击。它一直在发生。如果你运行联系表单却从未检查过邮件服务器日志,你很可能已经在以这种方式被利用。

发送联系表单邮件的正确方式

修复方法是永远不要把用户输入放进 From 头。应改为:

  • From: [email protected](或任何你控制的地址)
  • Reply-To: 用户提交的邮箱地址
  • Subject: 如有需要可以包含用户姓名,但绝不要包含其邮箱
  • Body: 包含所有表单数据,并清晰标注

这样,你的服务器只会从你拥有且已正确验证的地址发送邮件。当你在收件箱中点击“回复”时,邮件仍会发给用户——这正是 Reply-To 的作用。但垃圾邮件发送者无法利用你的表单冒充任意地址。

大多数邮件库都原生支持这一点。在 PHP 的 PHPMailer 中:

$mail->setFrom('[email protected]', 'Contact Form');
$mail->addReplyTo($_POST['email'], $_POST['name']);

在 Python 的 smtplibemail.mime 中:

msg['From'] = '[email protected]'
msg['Reply-To'] = form_data['email']

在使用 Nodemailer 的 Node.js 中:

const mailOptions = {
  from: '[email protected]',
  replyTo: req.body.email,
  // ...
};

如果你的联系表单目前把用户输入放进 From 头,这就是一行代码的修复。今天就做。

速率限制不是可选项

即使邮件头处理得当,一个没有保护的联系表单仍然是垃圾邮件入口。垃圾邮件发送者会用不同的消息内容提交你的表单数百次,你的收件箱会被垃圾信息填满。

你需要在多个层面设置速率限制:

  • 按 IP: 同一 IP 每小时不超过 5 次提交
  • 按邮箱: 同一邮箱地址每天不超过 3 次提交
  • 全局: 所有用户每小时不超过 50 次提交(根据你的流量调整)

速率限制应放在应用程序代码中,而不仅仅是 Web 服务器配置中。Nginx 和 Apache 的速率限制可以有所帮助,但它们在请求层面运作,并不了解邮箱地址或特定于表单的滥用模式。

如果你使用框架,通常会有可以直接接入的速率限制中间件。如果你从零开始构建,一个带过期键的简单 Redis 计数器就足够了:

key = f"contact_form:{ip_address}"
count = redis.incr(key)
if count == 1:
    redis.expire(key, 3600)  # 1 hour
if count > 5:
    return error("Rate limit exceeded")

这并非无懈可击——垃圾邮件发送者可以轮换 IP——但它会显著提高滥用成本。

CAPTCHA 是权衡,不是解决方案

Google 的 reCAPTCHA v3 是不可见的,并会根据行为给用户打分,听起来很理想。实践中,它阻止合法用户的频率往往高于预期,尤其是使用 VPN、Tor 或共享企业网络的用户。

reCAPTCHA v2(“I'm not a robot”复选框)更可靠,但会增加摩擦。蜜罐字段——人类不会填写但机器人会填写的隐藏表单输入——可以在不影响用户的情况下捕获低级机器人,但任何严肃的垃圾邮件发送者都能轻易绕过。

最佳方法是分层:

  1. 正确的邮件头(不可协商)
  2. 速率限制(不可协商)
  3. 蜜罐字段(容易实现且没有坏处)
  4. 只有在上述措施之后仍有大量垃圾邮件时,才使用 CAPTCHA

如果你确实添加 CAPTCHA,请使用 reCAPTCHA v3,并设置较低阈值(0.5 或更低),同时为得分较低的用户回退到 v2。这样可以让大多数用户保持低摩擦,同时仍能阻止机器人。

何时使用第三方表单服务

如果你运营的是小型网站,并且不想维护表单基础设施,Formspree、Tally 或 Netlify Forms 等第三方服务会为你处理这一切。它们会进行速率限制、验证,并从自己的域名发送邮件,因此你的声誉可以保持干净。

权衡之处在于,你会把用户数据发送给第三方,这可能与你的隐私政策或 GDPR 义务冲突。在客户端处理数据 是注重隐私的团队中日益增长的趋势,但联系表单本质上需要服务器端处理——你无法在不暴露凭据的情况下从浏览器发送邮件。

如果你处理敏感咨询(法律、医疗、金融),你很可能需要运行自己的表单基础设施。对于其他场景,第三方服务是一个合理选择。

DMARC 问题

即使你修复了联系表单的邮件头,如果你的域名缺少 DMARC 策略,你仍然不安全。DMARC 会告诉接收邮件服务器,在邮件未通过 SPF 或 DKIM 检查时该如何处理。没有它,垃圾邮件发送者仍然可以发送看起来来自你域名的邮件,即使他们没有使用你的服务器。

设置 DMARC 超出了本文范围,但如果你重视邮件声誉,这是不可协商的。先从仅监控策略(p=none)开始,并在确认你的合法邮件已正确通过身份验证后,逐步迁移到 p=quarantinep=reject

如果你的联系表单使用分析工具或营销像素来跟踪提交,你很可能受 GDPR 和 ePrivacy 规则约束。大多数联系表单不需要跟踪——你已经知道有人提交了表单,因为你收到了邮件——但如果你使用 Facebook Pixel 或 Google Analytics 事件之类的东西,就需要在这些脚本加载之前获得明确同意。

最简单的方法是完全不跟踪联系表单提交。如果你必须跟踪,请只在用户同意后加载跟踪脚本,并确保你的同意横幅合规。

关键要点

  • 永远不要把用户提交的邮箱地址放进 From 头。请改用 Reply-To
  • 速率限制是必须的。应在应用层实现,而不仅仅是在 Web 服务器层。
  • 蜜罐字段是免费的收益。CAPTCHA 应作为最后手段。
  • 第三方表单服务对小型网站来说是合理选择,但会带来隐私方面的权衡。
  • 如果你从自己的域名发送任何邮件,就需要 DMARC 策略。

FAQ

Q: 我可以直接禁用联系表单,改用 mailto 链接吗?

A: 可以,但 mailto 链接会把你的邮箱地址暴露给抓取工具,并且你会失去收集结构化数据的能力。如果垃圾邮件已经难以承受,mailto 链接比一个有问题的联系表单更好,但修好表单比两者都更好。

Q: 如果我出于正当原因需要从用户的地址发送邮件怎么办?

A: 你几乎肯定不需要。如果你认为需要,你很可能是在试图解决一个工作流问题(例如回复路由),而 Reply-To 已经解决了这个问题。如果你确实需要从任意地址发送邮件,你需要的是具备正确身份验证的专用邮件服务,而不是联系表单。

Q: 我如何知道自己的联系表单是否已经被滥用?

A: 检查邮件服务器日志中的外发 SMTP 连接。如果你看到大量发送到不认识地址的外发邮件,或者你的域名已被 Spamhaus 等垃圾邮件数据库标记,你很可能正在被用作中继。MXToolbox 等工具可以检查你的域名声誉。

Q: 使用免费的 CAPTCHA 服务安全吗?

A: Google 的 reCAPTCHA 免费且被广泛使用,但它会向 Google 发送用户数据,这可能与你的隐私政策冲突。hCaptcha 是一个注重隐私的替代方案,不会用你的用户训练 AI 模型。Cloudflare Turnstile 也是一个选项,比传统 CAPTCHA 更少打扰用户。

Q: SPF、DKIM 和 DMARC 有什么区别?

A: SPF 列出哪些邮件服务器被允许从你的域名发送邮件。DKIM 会对外发邮件进行加密签名,使收件人可以验证邮件未被篡改。DMARC 将二者关联起来,并告诉收件人在邮件未通过 SPF 或 DKIM 检查时该如何处理。要实现正确的邮件身份验证,三者都需要。

Sources

Five-step flow showing how a spammer abuses a contact form by putting a victim email in the From header, causing spoofed mail to pass through your server
InfographicHow a contact form turns into a spoofing relay — A simple five-step chain shows how one unsafe header turns your form into a spam relay
Side-by-side comparison of unsafe and safe contact form email headers, showing user email in From on the left and Reply-To on the right
InfographicWrong vs right contact form email headers — The safe pattern is simple: your domain in From, user input only in Reply-To
Checklist-style security stack for contact forms with exact rate limits, honeypot, and CAPTCHA fallback thresholds
InfographicLayered defenses for contact form spam — Start with headers and rate limits, then add honeypots, and only use CAPTCHA as a fallback

常见问题

我可以直接禁用联系表单,改用 mailto 链接吗?
可以,但 mailto 链接会把你的邮箱地址暴露给抓取工具,并且你会失去收集结构化数据的能力。如果垃圾邮件已经难以承受,mailto 链接比一个有问题的联系表单更好,但修好表单比两者都更好。
如果我出于正当原因需要从用户的地址发送邮件怎么办?
你几乎肯定不需要。如果你认为需要,你很可能是在试图解决一个工作流问题(例如回复路由),而 `Reply-To` 已经解决了这个问题。如果你确实需要从任意地址发送邮件,你需要的是具备正确身份验证的专用邮件服务,而不是联系表单。
我如何知道自己的联系表单是否已经被滥用?
检查邮件服务器日志中的外发 SMTP 连接。如果你看到大量发送到不认识地址的外发邮件,或者你的域名已被 Spamhaus 等垃圾邮件数据库标记,你很可能正在被用作中继。MXToolbox 等工具可以检查你的域名声誉。
使用免费的 CAPTCHA 服务安全吗?
Google 的 reCAPTCHA 免费且被广泛使用,但它会向 Google 发送用户数据,这可能与你的隐私政策冲突。hCaptcha 是一个注重隐私的替代方案,不会用你的用户训练 AI 模型。Cloudflare Turnstile 也是一个选项,比传统 CAPTCHA 更少打扰用户。
SPF、DKIM 和 DMARC 有什么区别?
SPF 列出哪些邮件服务器被允许从你的域名发送邮件。DKIM 会对外发邮件进行加密签名,使收件人可以验证邮件未被篡改。DMARC 将二者关联起来,并告诉收件人在邮件未通过 SPF 或 DKIM 检查时该如何处理。要实现正确的邮件身份验证,三者都需要。

来源与进一步阅读

  1. OWASP: Email Header Injection
  2. RFC 5322: Internet Message Format
  3. DMARC.org: Overview
  4. Spamhaus: Domain Blocklists
关于作者
The Wux Webtools Team

最后更新:

继续阅读