Web 端邮箱混淆技术
每一个公开的邮箱地址都是攻击目标。当你在 HTML 中放入一个裸露的 mailto: 链接时,自动化的爬虫程序可以迅速收集到它。本文将介绍前端开发者最实用的邮箱混淆技术——每种技术的原理、面对现代爬虫工具的有效程度,以及它们在可用性或可访问性方面的不足。
需要预先说明一个重要事项:邮箱混淆并不能保证安全。它只能减少自动化采集,无法阻止有针对性的收集。无头浏览器、AI 辅助爬虫和 OCR 工具的出现,使得几种较老的技术远不如以往可靠。我们的目标是提高采集成本,而非让发现变得不可能。
核心要点
- 裸露的
mailto:链接极易被爬取,会同时在href属性和可见的 DOM 中暴露你的地址。 - HTML 实体编码对基于简单正则的爬虫意外地有效,但对无头浏览器毫无防御能力。
- 基于 JavaScript 的技术(字符串拼接、转换函数、通过
SubtleCrypto实现的 AES)显著提高了基础爬虫的门槛。 - CSS 技巧如反转文本或
::after伪元素会损害可用性和可访问性——应避免使用。 - 联系表单避免在页面 HTML 中暴露地址,但应配合蜜罐字段或注重隐私的 CAPTCHA(如 Cloudflare Turnstile)使用。
- 多种技术分层组合可提供最佳的实际防护效果。
为什么裸露的 mailto 链接是个问题
一个未受保护的 mailto: 链接,例如:
<a href="mailto:contact@example.com">Email us</a>
极易被爬取。基于正则的机器人能瞬间发现它。它在两个地方暴露了你的地址:href 属性,以及——如果你将地址显示为链接文本——可见的 DOM。要想有效减少垃圾邮件,这两处都需要保护。
HTML 实体编码
将邮箱地址中的每个字符替换为其对应的 HTML 实体,是最古老的混淆技术之一:
<a href="mailto:contact@example.com">Email us</a>
浏览器会正确解码并渲染出可用的 mailto 链接。Spencer Mortensen 的蜜罐测试发现,这种方式拦截了高比例针对可点击链接的爬虫——考虑到服务端库可以轻松解码实体,这种效果令人意外。它之所以有效,是因为大多数爬虫并不复杂。然而,它对无头浏览器或任何处理渲染后 DOM(而非原始 HTML)的爬虫毫无防御作用。
可用性: 无影响。可访问性: 完全兼容。可维护性: 手写繁琐——请使用生成器。
基于 JavaScript 的混淆
JavaScript 技术将邮箱地址完全从静态 HTML 中移除,这显著提高了基础爬虫的门槛。
字符串拼接 将地址拆分到多个字符串片段中,在运行时进行组装。完整地址永远不会出现在 HTML 源码中,只在执行后存在于内存里。
<a id="contact-link" href="#">Email us</a>
<script>
const user = "contact";
const domain = "example.com";
const link = document.getElementById("contact-link");
link.href = "mailto:" + user + "@" + domain;
link.textContent = user + "@" + domain;
</script>
自定义转换函数 更进一步。HTML 源码中包含无意义的占位文本,只有在页面在真实浏览器环境中渲染时,一个小型 JS 函数才会将其转换为有效地址。这是 mailto 链接防垃圾邮件最有效的方法之一,因为它需要完整的 JavaScript 执行才能还原地址。
AES 加密 使用浏览器原生的 SubtleCrypto API,在构建时加密地址,并在客户端解密。由于 SubtleCrypto 只能在安全上下文中运行,这要求使用 HTTPS——而你本就应该已经在使用。根据 Can I Use 的数据,现代浏览器已广泛支持该 API。
重要局限: 这些技术都无法阻止 Puppeteer 或 Playwright 等无头浏览器,它们能完整执行 JavaScript。但它们能阻止大多数仍然基于正则、只处理原始 HTML 的爬虫。
可用性: 实现得当时极佳。可访问性: 取决于实现——确保渲染出的链接可通过键盘导航且对屏幕阅读器友好。可维护性: 中等。
应避免的 CSS 技术
一些 CSS 方法——反转文本方向、屏幕外定位或 ::after 伪元素——看似巧妙,但严重破坏可用性。通过 ::after 渲染的文本无法被选中或复制。反转文本即便能复制也会让用户困惑。这些技术也无法抵御任何同时解析 CSS 和 HTML 的爬虫。请避免使用。
Discover how at OpenReplay.com.
联系表单作为替代方案
用联系表单替代公开的邮箱地址,可以完全避免在页面 HTML 中暴露地址。代价是可用性:许多用户更倾向于直接发邮件,而较长的表单会降低转化率。
如果你使用联系表单,请保护好它。机器人可以自动提交表单。添加一个蜜罐字段——一个真实用户从不填写但机器人通常会填写的隐藏输入框——作为轻量级、可访问的第一层防护。对于流量较大的表单,Cloudflare Turnstile 提供了一种注重隐私的 CAPTCHA 替代方案,比 reCAPTCHA v2 的摩擦更小。
可访问性提示: 基于图像的 CAPTCHA 对视障用户造成实质性障碍。务必提供音频替代方案,或选择不依赖纯视觉挑战的 CAPTCHA 方案。WCAG 2.2 指南是一个很好的参考依据。
Cloudflare 邮箱地址混淆
如果你的网站在 Cloudflare 后端运行,其内置的邮箱地址混淆功能值得启用。Cloudflare 会在边缘节点重写你 HTML 中的邮箱地址,在页面到达客户端之前完成,然后注入一个延迟加载的小型解码脚本(email-decode.min.js),在浏览器中将其还原。该脚本以 defer 方式加载,因此不会阻塞渲染。
这种方法对用户实际上是透明的,且无需对代码库做任何修改。主要限制在于它不适用于 <script>、<noscript>、<textarea> 或 <head> 标签内部,并且如果你的页面带有 Cache-Control: no-transform 响应头,它也无法工作。
通过分层组合提升防护覆盖
没有任何单一技术能够独立胜任。对大多数网站而言,一个实用的组合是:
- 使用 JavaScript 转换或 AES 加密 保护 mailto 链接的
href属性。 - 对任何可见的地址文本应用 HTML 实体编码 作为辅助层。
- 添加带有 蜜罐字段的联系表单 作为替代联系方式。
- 如果你已在 Cloudflare 网络上,启用 Cloudflare 邮箱混淆。
这种分层方法同时覆盖了链接属性和可见文本,弥合了仅读取原始 HTML 的爬虫与执行 JavaScript 的爬虫之间的差距。
结论
邮箱混淆能切实减少自动化采集。蜜罐数据一致表明,即便是基础技术也能拦截大量爬虫,因为许多采集者仍然不够先进。但混淆并不能替代优秀的垃圾邮件过滤器,也无法阻止有决心的、针对性的收集。
实施一两种可靠的技术,在合理之处分层使用,然后继续前进。节省下来的时间最好用在别处。
常见问题
是的,但仅对不复杂的爬虫有效。蜜罐测试表明,它仍能阻挡许多基于正则的爬虫,因为它们读取原始 HTML 时不会解码实体。然而,任何解析渲染后 DOM 的爬虫(包括 Puppeteer 等无头浏览器)都能看到解码后的地址。请将其作为更广泛策略中的一层使用,而非独立防御。
可以。Puppeteer 和 Playwright 等无头浏览器能完整执行 JavaScript,因此任何依赖运行时解码的技术——包括字符串拼接、转换函数和 AES 解密——都能被它们击败。基于 JS 的混淆的价值在于阻止数量更庞大的基于正则的爬虫,后者仍占据自动化采集流量的很大比例。
这取决于你的目标。联系表单避免了在页面 HTML 中暴露邮箱地址,对基础采集提供了更强的保护。但表单会降低转化率,且许多用户更倾向于直接发邮件。一种平衡的做法是同时提供两者:为愿意使用的用户提供混淆的 mailto 链接,并配以带蜜罐字段的受保护联系表单作为后备。
通常不会有实质性影响,但仍应在真实页面和辅助技术上进行测试。解码脚本会在页面加载后于客户端还原地址,之后键盘导航通常可以正常工作。搜索引擎一般不将邮箱地址视为排名信号,因此实际的 SEO 影响很小。只需确保你的页面没有携带 Cache-Control no-transform 响应头即可。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.