版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7609137.html 作者:窗户 QQ:6679072 E-mail:6679072@qq.com
WAF(Web Application Firewall, Web防火墙)的实现有多种手段,基于regex(Regular Expression,正则表达式),然后编译成一个大状态机是目前主流的方式。当然,阿拉云安全的主架构师讲了个ppt,直接说regex来做防火墙有不合理的地方,理由是使用regex做防火墙,其计算复杂度最高的那一个regex是整个系统的短板,如果这个regex的时间复杂度过高,攻击者完全可以利用这一点攻击WAF达到DDOS的效果。从而,他觉得regex迟早应该退出WAF的领域,而用人工智能白名单的新一代WAF才是未来WAF的主流。这位仁兄说的是有道理的,正则表达式做的WAF异常复杂,运算强度高,这些瓶颈业内早就熟知,未来应当属于人工智能。接下去的相当一段时间,我也的确需要思考思考下一代的WAF是具体如何更好的结合人工智能。话说回来,毕竟在可预见的时间里,基于regex的WAF还是主流。吐槽一下,正则表达式真的是一个我不知道该说是天才还是该说是垃圾的翻译,让我每当写到一次就想吐槽一次。
话题有些扯远了,越是今天信息如此膨胀,WAF越是会偏向于用电脑来解决而非嵌入式设备,但和我要提到的话题牵涉到的都是包过滤。在信息膨胀的今天,百M甚至千M已经不能满足我们的需求,主干网上万M交换机用来满足大数据量的交换。速度太快,我们实在无法完全使用CPU来处理这一切,CPU只可以作为终端配置等功能,而对于万M网络本身的控制应使用ASIC(Application Specific Integrated Circuit,专用集成电路),也就是为此应用专门设计一个芯片,而非用于多种场合的通用芯片。然而ASIC无法升级,若要升级只能替换。FPGA可以替代这个,同时满足ASIC的需求和升级的需求,目前高端的FPGA的主时钟可以很快,但当然也挺昂贵。
想起大约十年以前,我们利用FPGA处理NGN信令,涉及到网络包的过滤、统计等。当时,我们对于包的过滤是半定死的,比如UDP还是TCP、端口需要不需要过滤、如果需要端口过滤端口多少、IP需要补需要过滤、如需要IP过滤IP如何过滤,如此设计是因为对于当时的应用来说也已经足够。
如果熟悉抓包工具,比如tcpdump,会想到平常的时候我们对于2~4层的抓包的确不会想WAF那样动辄regex作为判断条件,而是一堆基于固定位置(比如对于UDP包,其端口号、IP地址等在包中的偏移都是固定的)的数值等式或不等式作为bool值连成的bool表达式。我们就以tcpdump命令的参数来说明,比如tcpdump tcp and dst host 192.168.218.1 and src port 22,其中tcp、 dst host 192.168.1.1、src port 23就是三个不同的bool值。如果熟悉tcpdump和TCP/IP,对照资料,我们可以重新修改上述规则,把tcp、dst host、src port解析为偏移,从而整个规则写作偏移的形式。在绝大多数的应用下,一条过滤里面这样独立的bool值不超过8个。
硬件的好处是快速、直接,软件的好处是高扩展性,我们完全可以结合两者。用上位机(可能是控制的电脑,也可能只是内部的一个嵌入式CPU)把tcp and dst host 192.168.218.1 and src port 22这样容易阅读的东西翻译为偏移量、bool值这样的东西,并且给出各个bool值计算中偏移量从小到大排列,如果基础的bool值计算只有最多8条这样的情况,那么其实只需要FPGA内部做一个8位地址1位输出的RAM(可以设置,所以选择RAM而非ROM)即256bits的存储的RAM,上位机把RAM里面存储的所有值算出来并传给FPGA。
比如之前,tcp and dst host 192.168.218.1 and src port 22,3个bool值映射到1个布尔值,其实只需要2^3=8bits存储,8个bits分别为0,0,0,0,0,0,0,1,这就是RAM存储的内容。
甚至于,软件还可以比这个更加强大,可以考虑合并多条规则,切割多条规则,其实多条规则的多个bool表达式最终也通过and或者or来连接的,最后或许还有一个not,从整体来看归根结底还是一条规则。
用RAM来计算bool表达式虽说无法通用,因为其存储伴随着bool表达式的长度是乘方级的扩展,但简单、快。设计此类电路,简单就是美,对于电路的综合来说是至关重要的。并且,可以可以如此设置多条规则,但每条规则基本是独立工作。
随着FPGA收包的过程,依次匹配规则中的偏移量,计算出每个bool值,从而最终拼出查RAM的地址,从而查出该包是通过还是拦截。
我曾经考虑过用逆波兰式去计算,但对于这种场合似乎有很多的不方便,倒是RAM简单暴力直接。那可能会问,如何过滤规则过于复杂了怎么办,那就直接考虑不支持,任何产品都有一个设计规格,不可能无条件的满足所有人的需求。