案例分享:一封邮件如何影响整个邮件服务的解析

【】最近业界发现并公布了五大流行Node.js类电子邮件解析器的如下疑似漏洞,这些漏洞都属于隐蔽渐进式的拒绝服务(DoS)类型。

  • u Haraka的漏洞-https://snyk.io/vuln/search?q=haraka&type=npm?utm_source=dzone&utm_medium=content&utm_campaign=content_promo&utm_content=email_exploit
  • u mailparser的漏洞–https://snyk.io/vuln/npm:emailjs-mime-parser?utm_source=dzone&utm_medium=content&utm_campaign=content_promo&utm_content=email_exploit
  • u emailjs-mime-parser的漏洞–https://snyk.io/vuln/npm:mailparser-mit?utm_source=dzone&utm_medium=content&utm_campaign=content_promo&utm_content=email_exploit
  • u mailsplit的漏洞–https://snyk.io/vuln/npm:mailsplit?utm_source=dzone&utm_medium=content&utm_campaign=content_promo&utm_content=email_exploit
  • u mailparser-mit的漏洞–https://snyk.io/vuln/npm:emailjs-mime-parser?utm_source=dzone&utm_medium=content&utm_campaign=content_promo&utm_content=email_exploit

为了利用这些漏洞,可以通过在电子邮件中附上几百万个空的附件,来绕过典型的邮件大小限制(通常为20 MB或更少)。因此,当此类电子邮件被发送到脆弱的邮件服务器上时,由于附件数量过于庞大,所以它会让Node.js的事件循环(event loop)停滞几秒钟。

[[263460]]

同时,由于为每个附件都创建了一个内部对象,因此内存的使用量会马上“爆”到2 GB或者更多,从而让整个服务器因为内存的不足而崩溃。

那么,您真的确信自己的Node.js服务器能安全地解析电子邮件吗?下面,我将通过自己的亲身经历来和大家一起分析并检查电子邮件的解析器。

在开始深入探讨之前,让我们先来欣赏一下由XKCD(由Randall Munroe创作的著名的网络漫画。请参见https://xkcd.com/1873/)带来的“强迫症”漫画。

拒绝服务工具有那么简单吗?

由于依赖项的普及,上述漏洞一旦被利用,就会波及到数千个系统。例如:mailparser库(请参见https://www.npmjs.com/package/mailparser)每月的下载量就多达249,400次,并且目前已被214个其他项目(包括Sendgrid https://www.npmjs.com/package/@sendgrid/inbound-mail-parser)用作依赖项。而Haraka(请参见https://www.npmjs.com/package/Haraka)则是另一个影响深远的库,它正在被Craigslist(请参见https://www.craigslist.org/about/thanks)、Fort Anti-Spam(请参见https://www.fortantispam.com/)和ThreatWave(请参见https://haraka.github.io/users.html)所使用着。

通常,您大可不必请来Cloudflare(译者注:一家提供网站安全管理的公司)的专业服务与帮助,您完全可以自行通过添加一行简单的代码,来修复该问题。例如,您可以通过计算附件(包括那些文本部分)的数量,来验证用户数据的合法性。例如,您可以设定为:如果附件的数量超过1000,则采取丢弃之类的反应动作。

不过,此类修复只是一种治标不治本的被动防御,它在上述五种邮件解析器中的实现方式不尽相同,也不尽完全奏效。因此,我们必须通过如下的改进方式,来真正找到并修补此类漏洞。

想象一下,您正在编写一个邮件解析器……

作为一名开发者,您应该知道有多少份RFC需要阅读和掌握,也应该知道需要编写多少种测试,来确保自己的程序能够符合RFC的相关规定。同时,您也一定听过软件行业内的那句名言:“先让它运行起来,再让它运行得更快。”不过,这一套理论对于电子邮件解析器来说却不那么奏效。就算完成了邮件解析器的编写,您也无法仅仅通过粗略的背板计算(back-of-the-envelope calculation,请参见https://highscalability.com/blog/2011/1/26/google-pro-tip-use-back-of-the-envelope-calculations-to-choo.html),来估算出:在自己的应用中,应当分配多少数量的内存给一个包含了multipart的对象。而且,通过复杂的分析,您还可能发现如下问题:

  • 不止需要测试内存的用量,您还可能需要测量CPU使用率。
  • 您可能无法对那些典型的内存占用量,开展基准化的测试。
  • 由于最终的SMTP应用环境存在着不定性,因此就算90%的电子邮件确实为垃圾邮件,您也无法去启用任何一种快速的解析路径。
  • 您完全可以避免在解析器中执行太多、太严格的策略决策(policy decision)。
  • 您的用户可能并不买账,您对每封邮件采取的大附件数量的限制。
  • 由于不是邮件服务器的管理员,您可能会更愿意在SMTP的事务处理期间,完成了所有内容的解析之后,让用户自行去判断和拒收某些邮件。

想象一下,您正在运行一个电子邮件服务器……

鉴于上述情况,您需要做的事就是:设置邮件的大小限制。显然,邮件越大,它被服务器接收的可能性就越小。因此,为了将解析时间控制在合理范围内,您可以将单封邮件的体积上限限制为20MB。籍此,您就可以放心地使用那些“经过实战考验”的、时下流行的邮件解析器。

为了简化邮件解析器的复杂性,您可以直接将处置20MB电子邮件时的CPU使用率作为参考基线准,以保证自己的服务器能够每秒处理数千封邮件。因此,假设服务器处理相同大小邮件的时间就是恒定的,那么您只需要8GB的内存,便可足够应对每秒200封且大小为20MB的邮件并发量了。有了这样的简化场景,您后续只需要考虑带有0字节的附件,即空文件的安全危害即可。相关概念请参见:https://en.wikipedia.org/wiki/Zip_bomb。下面是一个简单的范例:

  1. MIME-Version: 1.0 
  2. From:  
  3. To:  
  4. Subject: MIME Multipart Attack 
  5. Date: Sat, 30 Jun 2018 15:51:58 +0000 
  6. Message-ID:  
  7. Content-Type: multipart/mixed; boundary="0" 
  8. --0 
  9. Content-Type: text/plain; charset=UTF-8 
  10. Content-Transfer-Encoding: quoted-printable 
  11. --0 
  12. --0 
  13. --0 
  14. --0 
  15. --0 
  16. --0 
  17. --0 
  18. --0 [× 4 million] 

如何发现此类漏洞?

回到开始提到的案例,我曾经遇到过:由于一个奇怪的入栈邮件,突然导致了V8(一种JavaScript引擎)的垃圾收集器一次性地阻止了Node.js的事件循环长达几十秒。我为此花费了两天的时间,每隔几分钟就去重置feature-flags,以减少邮件队列的负荷。在Vyacheslav Egorov(请参见https://github.com/mraleph)的帮助下,我注释掉了V8的CollectAllAvailableGarbage函数(请参见https://github.com/v8/v8/blob/master/src/heap/heap.cc#L1237)。该函数的内部工作原理是:对那些巨大的(几个GB大小)堆栈随机进行七次收集。由此,我所吸取到的教训是:应当谨慎地对堆栈进行对象分配,进而避免对事件循环的阻断。

从去年年初开始,我不断在开源社区–https://github.com/ronomon/mime上编写并更新自己的邮件解析器。我的目标是:希望新的版本能够具有更快的解析速度、更少的资源分配数、能够在原始的缓冲区上运行、以及对RFC具有100%测试覆盖率(包括模糊测试,fuzz tests)。

在此过程中,我进一步了解到:策略决策会比邮件服务器本身更有利于邮件的解析;同时,邮件的解析也会反过来促进策略的决策。此处的策略决策包括:拒绝明显的恶意代码,拒绝各种损坏的、或被截断的Base64、以及Quoted-Printable之类的字符编码,拒绝重复性的关键标题(请参见https://noxxi.de/research/content-transfer-encoding.html),限制multipart的数量,以及限制由于对multipart边界的误报而引起的回溯。

今年初,我与《避免阻断Node.js事件循环的完全指南》(an excellent guide to not blocking the Node.js event loop,请参见https://nodejs.org/en/docs/guides/dont-block-the-event-loop/)一文的作者–Jamie Davis取得了联系。Jamie在文中所讨论的如何抵御事件循环风险,正是我在本文中提及的,针对邮件解析器的multipart风险。

九点改进建议

在此,我为大家列出了针对此类问题的九项值得尝试的实践:

1. DoS对于资源稀缺的系统更容易产生效果。作为知识的积累,您可以通过《mechanical sympathy》(https://mechanical-sympathy.blogspot.com/2011/07/why-mechanical-sympathy.html)一文,来了解底层硬件是如何运作的,以及如何通过编程,实现与底层硬件的良好协作。由于解析的算法既会涉及到CPU的使用,又会涉及到内存的分配,因此我们需要事先合理地配置好硬件资源。如果您的代码能够有效地使用CPU、内存、磁盘、及网络的话,那么您可能就不太会碰到资源匮乏的问题。当然,您仍需要对所有的系统资源,进行合理的使用限制。

2. 在设计之初,就从不同的资源维度进行粗略的背板计算。此法能够尽早地暴露并发现设计中的缺陷,进而避免产生那些“不可能”的解析。由于系统的性能和安全性通常很难通过后期的优化而有所改进,因此它们需要在初期就被规划好,而不要等到用户使用量上去了,才“亡羊补牢”。

3. 平衡所有维度上的资源使用情况。不要出现:您虽然尚有足够的CPU去满足吞吐量的需求,但早已耗尽了内存的情况。因此,您同样需要通过粗略的背面计算,来保持各类资源的使用占比,以避免产生各种设计中的潜在瓶颈。

4. 记住:在运行事件循环时,大多数性能问题都源自拒绝服务式的等待。因此,如果有用户报告性能问题,那么您首要检查的应该就是安全方面的风险可能性。

5. 验证所有用户的入栈数据,不仅要考察单位时间的数据量,还应当检查一段时间的总量。某些风险往往会以潜移默化的方式,对您的邮件系统进行逐步渗透,然后产生倍数效应,并最终接管您的系统。

6. 注意模块边界之间的“空白地带”。不要依赖其他的开发伙伴去帮助您弥补这些不足之处。为了避免策略决策上的缺陷,您应当更好地了解代码间的依赖关系。

7. 从整体的安全角度出发,制定严格的过滤策略,对于不确定是否“健康”的邮件,系统应当坚决“拒之千里之外”。

8. 不要只是从开发人员的角度去检查自己的代码,而需要从恶意击者的角度出发,考虑他们会如何利用那些邮件解析中的代码漏洞。在程序发布之前,请在每个模块中至少仔细地检查并修复三个漏洞。

9. 编写简单的模糊测试用例(请参见https://en.wikipedia.org/wiki/Fuzzing),以随机生成各种有效的和无效的参数。针对某个函数相对其他函数的返回值,请测试其有效性、正确性、以及各种无效的异常输出。您可以根据Linus极端法则(请参见https://en.wikipedia.org/wiki/Linus%27s_Law),运行具有数百万个参数组合的函数模糊测试。

私有与公共披露时间表

该漏洞已于2018年4月23日向受影响模块的所有者进行了披露。不过,就在90天的公开披露截止日期到期之前,该所有者以某种理由推迟了对它的公开披露。此后,通过联系与之相关的依赖项模块(主要是在GitHub上),该漏洞已于2018年6月25日得到了全面公开与披露。

另外,有关这五大Node.js类邮件解析器的DoS漏洞介绍和具体信息,请参见下表:

1. haraka (versions < 2.8.19)

https://snyk.io/vuln/npm:haraka:20180625

  • April 23rd, 2018 – Initial private disclosure to package owner
  • April 24th, 2018 – Initial response from package owner
  • June 15th, 2018 – Vulnerability fixed but not yet published to npm
  • June 25th, 2018 – Public disclosure
  • June 27th, 2018 – Version 2.8.19 published with fix

2. mailparser (ALL versions)

https://snyk.io/vuln/npm:mailparser:20180625

  • April 23rd, 2018 – Initial private disclosure to package owner
  • April 24th, 2018 – Initial response from package owner
  • June 25th, 2018 – Public disclosure

3. emailjs-mime-parser (ALL versions)

https://snyk.io/vuln/npm:emailjs-mime-parser:20180625

  • April 23rd, 2018 – Initial private disclosure to package owner
  • April 24th, 2018 – Initial response from package owner
  • June 25th, 2018 – Public disclosure

4. mailsplit (versions < 4.2.1)

https://snyk.io/vuln/npm:mailsplit:20180625

  • April 23rd, 2018 – Initial private disclosure to package owner
  • April 24th, 2018 – Initial response from package owner
  • June 25th, 2018 – Public disclosure
  • July 23rd, 2018 – Version 4.2.1 published with fix

5. mailparser-mit (ALL versions)

https://snyk.io/vuln/npm:mailparser-mit:20180625

  • April 23rd, 2018 – Initial private disclosure to package owner
  • April 24th, 2018 – Initial response from package owner
  • June 25th, 2018 – Public disclosure

原文标题:How to Crash an Email Server With a Single Email,作者:Liran Tal

【IDC.NET译稿,合作站点转载请注明原文译者和出处为IDC.NET.com】

 

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/128711.html<

(0)
运维的头像运维
上一篇2025-02-25 06:49
下一篇 2025-02-25 06:50

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注