使晶片速度提高40%

2020-07-01 22:04:13

CloudFlare的Web应用程序防火墙(WAF)可防御旨在利用Web应用程序中的漏洞进行的恶意攻击。它不断更新,以提供针对最新威胁的全面覆盖,同时确保较低的误报率。

与所有Cloudflare安全产品一样,WAF的设计不会为了安全而牺牲性能,但总有改进的空间。

这篇博客文章简要概述了向我们的客户推出的最新性能改进。

早在2019年7月,WAF就从使用基于PCRE的正则表达式引擎过渡到受RE2启发的引擎,该引擎基于确定性有限自动机(DFA),而不是回溯算法。此更改是由于停机造成的,其中更新添加了一个正则表达式,该正则表达式在某些HTTP请求上会产生巨大的回溯,从而导致指数级的执行时间。

迁移完成后,我们在边缘的CPU消耗方面没有看到可测量的差异,但是注意到第95和第99个百分位数的执行时间异常值降低了,这是我们预期的,因为RE2保证了与输入大小成线性关系的执行时间。

由于WAF引擎使用线程池,我们还必须实现和调优线程之间共享的正则表达式缓存,以避免过度的内存消耗(第一个实现使用了惊人的内存量)。

这些变化,以及事后博客文章中概述的其他变化,帮助我们提高了边缘的可靠性和安全性,并有信心探索进一步的性能改进。

虽然我们已经强调了正则表达式,但它们只是WAF引擎众多功能中的一个。

当HTTP请求到达WAF时,它被组织成几个逻辑部分进行分析:方法、路径、头和正文。这些部分都存储在Lua变量中。如果您对WAF本身实现的更多细节感兴趣,您可以观看这个旧的演示文稿。

在将这些变量与特定的恶意请求签名进行匹配之前,会应用一些转换。这些转换是一系列函数,从简单的修改(如低位字符串)到复杂的标记器和解析器(寻找某些恶意有效负载的指纹)。

由于WAF当前使用ModSecurity语法的变体,因此规则可能如下所示:

它获取存储在REQUEST_BODY变量中的请求体,对其应用urlDecode()和lowercase()函数,然后将结果与正则表达式签名\x00+evy进行比较。

其正文包含百分比编码的空字节后跟单词“邪恶”的请求将与之匹配,例如:

WAF包含数千条这样的规则,其目标是尽可能快地执行这些规则,以最大限度地减少请求的任何额外延迟。让事情变得更难的是,它需要对几乎每个请求运行大多数规则。这是因为几乎所有的HTTP请求都是非恶意的,没有规则会匹配。因此,我们必须针对最坏的情况进行优化:执行所有操作!

为了帮助缓解此问题,对许多规则执行的第一个匹配步骤之一是预筛选。通过检查请求是否包含某些字节或字符串集,我们可以潜在地跳过相当数量的表达式。

在前面的示例中,快速检查空字节(在正则表达式中由\x00表示)允许我们在找不到规则时完全跳过它:

由于大多数请求都不匹配任何规则,并且这些检查执行得很快,因此总的来说,我们不会通过添加它们来执行更多操作。

还可以使用其他步骤来扫描和组合多个正则表达式,避免执行规则表达式。像往常一样,做更少的工作通常是让系统变得更快的最简单的方法。

这就引出了记忆化--缓存函数调用的输出,以便在将来的调用中重用它。

1.RX(";\x00+EVISH&34;,小写(url_decode(Body)2.RX(";\x00+EVISH";,Remove_Spaces(url_decode(Body)3.RX(";\x00+EVISH";,小写(url_decode(Headers)4.Streq(";\x00 Evide";,小写。

在这种情况下,我们可以重用嵌套函数调用(1)的结果,因为它们与(4)中的结果相同。通过保存中间结果,我们还可以利用(1)中的url_decode(Body)结果,并在(2)和(4)中使用它。有时还可以交换应用于改进缓存的函数的顺序,尽管在这种情况下我们会得到不同的结果。

该系统的简单实现可以是哈希表,其中每个条目都将函数名和参数作为关键字,并将其输出作为值。

其中一些函数很昂贵,缓存结果确实会带来显著的节省。为了给人一种量级的感觉,我们修改了一条规则,以确保发生Memory,其中一条规则的执行时间减少了大约95%:

WAF引擎实现了内存化,规则也利用了这一点,但总有增加缓存命中率的空间。

CloudFlare定期发布托管规则集的更新和新规则。然而,随着更多规则的添加和新功能的实现,内存缓存命中率有下降的趋势。

为了改进这一点,我们首先使用我们的一些性能指标研究了执行时间最长的规则:

有了这些,我们将它们与具有缓存未命中的那些进行交叉引用(输出用[.]截断):

[电子邮件受保护]$./parse.py--profileHit比率:-0.5608热门条目:-[urlDecode,replaceComments,Request_URI,Request_Headers,args_POST][urlDecode,Request_URI][urlDecode,htmlEntityDecode,jsDecode,replaceNulls,remove[urlDecode,htmlEntityDecode,jsDecode,replaceNulls,remove.。REQUEST_HEADER,ARGS_POST][.]Candidates:-100152A-将t:removeWhitespace替换为t:压缩空白,t:removeWhitespace100214-将t:小写替换为(?i)100215-将t:小写替换为(?i)100300-考虑REQUEST_URI OVER REQUEST_FILENAME100137D-颠倒t的顺序:replaceNULL,t:小写[.]。

在确定了40多条规则后,我们重写了它们,以充分利用备忘录,并在可能的情况下添加了预过滤检查。其中许多变化并不是立竿见影的,这就是为什么我们还在创建工具来帮助分析人员创建更高效的规则。这还有助于确保它们按照团队设置的延迟预算运行。

此更改导致缓存命中率从56%增加到74%,这一点至关重要,其中包括最昂贵的转换。

最重要的是,我们还观察到WAF在Cloudflare边缘处理和分析HTTP请求的平均时间大幅减少了40%。

虽然Lua WAF在这些年来一直很好地为我们服务,但我们目前正在将其移植到使用相同的引擎来驱动防火墙规则。它基于我们的开源WireFilter执行引擎,该引擎使用受Wireshark®启发的过滤器语法。除了允许更灵活的过滤器表达式外,它还提供了更好的性能和安全性。

然而,在迁移到新引擎时,我们在这篇博客文章中描述的规则优化并没有丢失,因为这些更改故意不是特定于当前Lua引擎的实现。虽然我们经常对防火墙堆栈进行性能分析、基准测试和复杂的优化,但有时仅仅是相对简单的更改就可以产生令人惊讶的巨大影响。

晶片性能