最近发现五个最流行的Node.js电子邮件解析器容易受到简单的拒绝服务(DoS)漏洞的攻击。通过将数百万个空附件打包到绕过典型电子邮件大小限制(通常为20 MB或更小)的电子邮件中,可以攻击该漏洞。当电子邮件发送到易受攻击的电子邮件服务器时,由于附件数量庞大,它将冻结Node.js事件循环数秒。由于为每个附件创建的内部对象,内存使用量将激增至2 GB或更多,这通常足以在内存不足的情况下使整个服务器崩溃。那么,您的Node.js服务器可以解析电子邮件吗?您知道您使用的是哪个电子邮件解析器吗?在你检查之前,让我们看看这会影响到谁。
该漏洞易于解释、易于攻击,并影响数千个系统。例如,mailparser库每月接收多达249,400次下载,并被包括SendGrid在内的214个其他项目用作依赖项。Haraka是另一个受影响的库,它已经被Craigslist、Fort Anti-Spam和ThreatWave使用过。
修复是一个简单的俏皮话。你又不需要云耀斑。您只需要验证用户数据。这可以通过计算附件(包括文本部分)的数量并在附件计数超过1000个或更多的情况下做出反应来实现。您最后一次看到包含10,000个附件的电子邮件是什么时候?您什么时候需要发送100,000个附件?如果你还在分析一百万个附件,…。嗯,你知道你做得太过分了!
等等,我们怎么会错过这个呢?如果它真的像我们声称的那样容易修复,那么为什么至少有五个实现都是错误的呢?此外,我们是如何发现漏洞的,我们可以做些什么来改善呢?
您知道需要阅读(和解释)多少RFC。您知道需要编写多少测试才能确保尽可能符合RFC。您已经听说过“让它工作,然后让它快起来”这句软件咒语。但是电子邮件解析器很难,如果它能正常工作,你会很开心的。一旦您编写了一个,您就会开始理解为什么不进行快速的粗略计算来估计设计中的单个多部分对象可能分配多少内存。如果您执行复杂性分析,请执行以下操作:
您可能只根据CPU而不是内存进行测量。您可能不会对典型的内存占用进行基准测试。您最终对任何SMTP环境都是不可知的,因此您不会在解析器中尝试任何快速路径,即使90%解析的电子邮件将是垃圾邮件。您可以避免在解析器中强制执行太多严格的策略决定。您的用户可能不喜欢每封电子邮件的最大附件数限制。如果需要,您宁愿解析所有内容,并让用户在SMTP事务期间拒绝电子邮件。事实上,您毕竟不是电子邮件服务器管理员。
你可能要做的第一件事就是决定你的电子邮件大小限制。电子邮件越大,其他服务器接受它的机会就越小。您将电子邮件大小限制设置为20MB,认为这也应该将解析时间保持在合理的范围内。您决定使用流行的、经过战斗测试的电子邮件解析器。您相信电子邮件解析器的复杂性是线性的或电子邮件大小为O(N)。您以20MB的最大电子邮件大小为基准测试CPU使用率,并期望您的服务器每秒处理数千封邮件。您预计所有20MB电子邮件所需的时间大致相同。您认为只要8 GB的RAM就足以容纳每秒200封并发的20MB电子邮件,因为您并不指望您的用户群会增长那么快。如果有人和你打赌--你的服务器是否能处理10封并发的20MB电子邮件--你会很有信心。您脑海中的最后一件事是0字节附件。空文件有什么害处呢?