背景
WAF作为基础安全能力建设的必要一步,在为业务提供抵御Web攻击方面,发挥着重要作用,但是不管是公司内部自研WAF还是购买成熟的商业WAF产品,都绕不过一个问题——如何保证WAF不会降低业务的稳定性。举个例子,如果WAF挂了,怎么能保证业务正常运行?旁路部署,就能很好的解决上述问题,既可以测试WAF产品性能和稳定性,也不会影响业务。
那旁路部署,如何把流量输出给WAF,就很关键了。是在网络设备上做全流量镜像,还是通过日志恢复,又或者是应用业务程序把请求多转发一次?每一种方法实施的成本和对业务稳定性影响各不一样,下面一一说明。
流量镜像
流量镜像分为两个方面:网络设备上做和应用层软件层面做,以下分别说明这两种方式优缺点:
交换机流量镜像
流量镜像应该是旁路部署最常用也是最适合的方式了。在网络设备(如交换机)上直接通过一条命令,把指定网络端口流量,完全镜像到另外一个端口。这种方法的好处是:
- 业务完全无感知
- 数据和实际业务收到的数据一致
- 操作简单
但缺点也很明显 - 业务流量大的话,对网络设备性能是个考验。
- 如果流量加密的话,是否能解密值得商榷。
- 公有云场景下无法使用。比如用的是阿里云
- 是否有网络流量汇聚点。
可以看出,流量镜像虽然简单,易操作,影响小,但真正想让WAF发挥作用或者测试WAF功能,依然有很多问题要解决。
Nginx流量镜像
nginx流量镜像分为三种方式,三种方式操作各不一样
- nginx_mirror_module
Nginx1.13.4开始引入了nginx_mirror_module模块,这个模块的作用是把指定的流量转发到目标服务器,但需要注意的是,这个模块会丢弃目标响应,效果和交换机网络流量镜像一样。因为默认该模块不在nginx编译参数中,所以要使用这个模块的话,需要重新编译Nginx并且版本要大于1.13.4。但这个模块有个致命的缺点,复制的镜像请求和原始请求是相关联的,若镜像请求没有处理完成,原始请求就会被阻塞。 - openresty ngx.location.capture
该模块用于发起一个异步非阻塞的子请求到Nginx internal路由,同样,该模块也是忽略子请求的相应。所以,不会打断业务流程,类似的还有ngx.location.capture_multi模块。但这个模块有两个缺点,缺点一:无法转发到外部的服务器,必须配合upstream才可以。缺点二:http2支持不完全,存在bug,目前作者还没有解决。感兴趣的可以关注作者更新。最后,该模块在1.17.8.2之前的版本中存在一个CVE-2020-11724漏洞,使用的时候,需要注意。
请求转发
应用层请求转发
最后一种思路,就是在应用层,把web请求相关的数据,解析出来构造新的http请求,转发给WAF。这样做,对应用层来说可控性相对较高,但相应的,性能消耗也比较高,如果业务已经存在类似于APIGateway之类的应用层转发系统,那么实现起来相对会容易一些。
但应用层转发请求,是无法把服务器响应的数据发给WAF的,这样,WAF检测只能是单向流量的检测。对于想基于返回数据检测的WAF规则,就失效了。比如返回数据量大小、敏感数据检测等
- openresty lua-resty-http 库
lua-resty-http是openresty的一个http client库,可以在nginx配置文件中便编写lua代码,解析web请求相关的字段和数据,然后重新构造http请求数据,把用户的请求转发给WAF。虽然这个方法看似比较简单,但是需要一定的编码,比如转发哪些数据?这些数据都需要调用相应的Nginx moudle去获取,比如Header、url、body,如果是文件的话,还需要解析响应的文件。 - 应用层业务代码
类似于Gateway之类的应用层转发控制程序,也是可以把web请求的数据,通过构造新的HTTP请求,转发给WAF,但这样的话,对应用层代码的改动和对应用层转发业务的性能消耗都需要业务方考虑。安全部门需要业务部门的配合,才能够实施。技术上难度不大,主要是能否推动业务部门修改。
基于日志还原请求
最后一种办法,是基于Nginx或者其他类似的web服务器日志,还原HTTP请求。可以通过把请求的相关数据输出到日志文件中,另外安全部门可以开发相应的脚本,根据日志还原流量。但是这个方法在业务流量低的场景实现比较容易,对于web请求量比较大的场景,存在两个问题:
- 日志输出的多影响机器性能
- 打印消耗大量的磁盘IO
总结
本片文章主要介绍了几种把web请求流量打给WAF的方法,从而能够使用WAF检测Web攻击,识别当前服务安全风险。各个公司、各个业务对安全的诉求不同,想要达到的效果也不同,因此,安全部门在建设安全能力时,应充分了解业务的诉求,从而选择合适的方案,部署WAF。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。