公告 / 【vk技术分享】VK-WAF工作实践总结

作者:Jackuni 公布时间:2020-04-27 阅读次数:418

前言

WAF(Web Application Firewall)作为企业安全防护体系不可或缺的一环,承担着防御Web攻击的重任。不同的企业对WAF也有着不同的实践,这篇文章我们总结了VIPKID WAF相关的一些工作,希望能够抛砖引玉,通过业内交流,互相学习互相促进。本文第一部分是WAF选择及VIPKID WAF的架构介绍。第二部分是如何通过测试来验证WAF方案是否满足要求。第三部分是对CC攻击防御方案的一些介绍。第四部分介绍了我们踩过的一些坑及处理方法。




一.WAF的选择

WAF的选择主要取决于企业的业务需求,包括整体技术架构、安全预算等。有实力的企业可以根据需求自研WAF,这样会比较贴近业务场景,不过需要很大的投入。更多的企业可能会选择购买商业WAF,或者基于商业WAF进行二次开发以满足自身需求。安全预算比较少的企业,业务场景对WAF可用性和稳定性应该也不会很高,可以选择一些免费或者开源的WAF。商业、开源的WAF都有很多,从部署形态来讲,WAF可分为:云WAF、软件类WAF、硬件类WAF。


云WAF
云WAF近年来的市场占有率越来越高,根据FreeBuf《2020国内WAF产品研究报告》,现在云WAF的比例占到了39.4%,未来应该会有更多的企业选择使用云WAF。


>>>>云WAF的优势

  • 部署成本低,无需单独部署,无需单独维护。
  • 接入简单,通过DNS解析即可接入。
  • 安全运营成本低,出现新漏洞时厂商可以直接动态更新进行防御,不需要用户过多干预。



>>>>云WAF的缺点

  • 云WAF一般采用CNAME解析方式进行接入,一旦源站IP地址被泄漏,攻击者可以通过绑定hosts绕过WAF防御。
  • 走云WAF需要多一层公网转发,整体链路的网络延迟会增加。
  • 云WAF可支持的最高QPS有限。



软件类WAF
软件类WAF成本低,有多种免费或开源产品,比如:Modsecurity。可以直接安装使用,适用于一些中小型业务场景,但不适用于比较大型的业务场景。


硬件类WAF
硬件类WAF属于传统型的WAF,业务部署在公司自建机房或者IDC机房的传统企业可能会选择硬件类WAF,硬件类WAF基于硬件设备实现,可以承受较高的数据吞吐量。但在如今“全民上云”的大趋势下,硬件类WAF有些难以满足。根据Garter 2019 WAF魔力象限预测的数据,硬件类WAF目前占比30%,到2022年将会降低到10%。



VIPKID WAF选择

xVIPKID采用了双云高可用的技术架构,业务同时运行在多个云平台上。基于这个背景,我们最终确定的WAF方案为:私有化部署的WAF集群,以反向代理的方式串联至整体链路,然后通过统一管理平台对多个WAF集群进行集中管理。

示意图如下: 



>>>>这种WAF架构的优势1.所有需要开放到公网的域名都必须得经过WAF。
2.WAF转发在内网进行,延迟很低。(转发和检测可在1ms内完成。)
3.WAF集群具有容灾功能,后端服务器出现问题时可实现自动摘除。
4.可以在WAF层进行统一监控,监测CC攻击等恶意行为。

//缺点:链路经过的的代理比较多,如果出现问题排查的难度比较大。
>>>>为什么不使用单纯的云WAF?除了上述云WAF的一些缺点之外,在我们的业务场景下云WAF存在的最大的问题:无法满足我们多云多链路分组转发的场景需求。


二.WAF的测试

要把WAF串联在整体链路,那么WAF必须得有足够高的稳定性和高可用性,这个是基础。为了确认WAF的稳定性以及安全防御能力是否满足需求,在最终上线前,要对WAF做充足的测试。这个阶段很关键,测试时多发现一个坑,上线后就能少踩一次雷。为了确保对WAF可以进行全面的测评,需要制定一个详细的测试方案,罗列所有需要测试的项目,比如:WAF性能、WAF防御功能、WAF自身安全性、WAF日常运营功能等。


WAF性能测试

因为串联在整体链路,WAF的性能决定着链路整体的处理能力,所以WAF的性能尤为重要。一般WAF厂商会提供WAF产品的性能报告,不过私有化部署的WAF因环境配置不同会引起实际差异,所以需要实际测试确认。相对而言,运维、QA人员更关注WAF的性能,在制定实际测试方案时,可以联合他们一起参与WAF测试,毕竟关系到整体链路的稳定,而且这些方面他们更专业。

>>>>测试项1.WAF正常检测可支撑的最高QPS,对应负载下CPU、内存等资源的使用率,整体处理延迟。

2.WAF各项参数的配置与整体链路其他配置是否适配。
3.WAF在极端情况下的处理情况,比如:后端服务器响应慢或者down掉时WAF的运行情况。
4.WAF集群容灾模式的生效情况。

>>>>测试方法
1.对整体链路中包括WAF在内各层代理的配置参数进行统一评估、调优。(这一步可由运维架构师完成,做整体评估)
2.使用压测机对WAF做压测,测试WAF的极限负载指标。
3.模拟后端服务器慢响应等异常场景,观察WAF的运行情况。


WAF安全防御功能测试

>>>>测试项

1.对常见WEB安全漏洞的拦截情况:误报率、检出率、漏报率。
2.自定义拦截规则可配置的维度。
3.自定义拦截生效的时间。
4.CC攻击防御方案。

>>>>测试方法
可以通过模拟攻击来测试WAF的安全检测能力,比如搭建漏洞演练网站并接入WAF,通过发送各种漏洞的攻击payload,查看该WAF的检出率和漏报率。详细可以参考:《从甲方的角度谈谈WAF测试方法》。
检测WAF误报率最好的方法就是使用真实的或接近真实的业务流量去测试WAF,比如可以将WAF接入到测试环境或者pre环境,开启观察模式后统计WAF的检测记录。任何WAF都难免会出现误报,这里主要是评估WAF在企业的业务流量中误报率高不高,能否接受,发现误报后处理的措施等。

在日常WAF运营中,经常要添加自定义规则对攻击进行精准拦截,所以自定义规则的维度就决定了它的精准度和灵活度。另外在攻防分秒必争的场景下,拦截的生效时间肯定越短越好。这个比较简单,实际配置规则测试就好。

有些WAF厂商提供了一些默认的CC攻击防御规则,可以确认这些防御措施能否满足自身业务的CC攻击防御场景。CC攻击防护相对特殊,下面单独进行说明。


WAF自身安全性测试

WAF本身也是线上系统,必须得经过安全测试。现实的攻击入侵中,不乏通过安全产品的缺陷达到入侵目的案例。越是安全防御系统,其本身的安全性也越要重视。

可以对WAF本身进行一次完整的安全评估测试,比如WAF管理端有没有常见的Web漏洞,WAF本身有没有拒绝服务漏洞等。


WAF日常运营功能

如果不进行日常运营,那么WAF大概率会成为一个摆设。

WAF相关的运营工作包括:多个WAF集群的统一管理、域名的添加与管理、WAF整体监控、WAF的误报分析、整体WEB攻击的态势感知等。一款理想的WAF产品,应该很好的支持这些功能,或者支持自定义设计以实现上述功能。


WAF运营工作相对有些枯燥,有必要把这些工作实现自动化。所以关于WAF另一个需要考虑的问题就是:WAF产品有没有提供足够的API?有没有详细的说明文档?能否很好的支持二次开发?


WAF运营方面我们碰到的另一个问题:如何及时发现WAF的误拦截行为。以前用户被误拦之后我们无法及时感知,当用户反馈给客服再通过工单联系到我们时已经过去了很久,误报不能得到及时处理,这样的用户体验太不好了。如何有效的解决这个问题?一种方案就是自定义设计WAF拦截页面,修改页面的显示信息,并添加误报反馈功能。这样用户被误拦之后可以实时反馈给我们。所以WAF产品能否支持自定义拦截页面,这个也成为我们衡量的指标。


以上是基于我们业务场景考虑的一些测试项,不同企业在实际操作中可能会有一些特殊的业务场景需求。可以提前把这些需求罗列出来,添加到测试方案中。另外,在制定整体的测试方案时可以参考一些已有的WAF测评文档,比如OWASP的《WEB应用防火墙测评基准 V1.0》。


三.CC攻击防范

CC攻击,全称为challenge collapsar攻击,是DDoS的一种,属于应用层的DDoS攻击。攻击者一般通过发送恶意的HTTP请求,以达到耗尽服务器资源,导致其无法正常服务的目的。


CC攻击简介

常见的CC攻击包括:通过海量请求耗费服务器资源的攻击、慢速攻击、利用特定漏洞发起的CC攻击。

常规的CC攻击原理比较简单,通过大量请求比较耗费资源的接口,尤其是全盘搜索等需要大量数据库操作、需要大量CPU时间的的接口,导致服务端CPU占用100%,无法处理正常的业务请求。攻击者可能利用僵尸网络、或者大量的免费代理向目标发起攻击,当然某些神秘玩家也会借助一些大流量网站发起攻击,利用这些网站的xss漏洞或者直接进行js文件劫持,让这些大站的用户不断访问被攻击网站,使得被攻击网站访问量骤增。

HTTP慢速攻击利用了HTTP协议的一些“缺陷”达到攻击目的,有几种类型:Slow headers、Slow body、Slow read。慢速攻击主要利用的是thread-based架构服务器的特性,这种服务器会为每个新链接打开一个线程,等待接收完整该HTTP头部才会释放连接。像Apache、httpd采用了thread-based架构,很容易遭受攻击,而NGINX使用的是event-based架构,不容易遭受慢速攻击。

还有一种CC攻击是利用服务本身存在的漏洞,比如低于1.2.60版本的fastjson在解析包含某些特定转义字符的字符串时会引发OOM,从而导致CPU/RAM过载,造成服务器宕机。这种CC攻击比较有针对性,攻击者需要对被攻击业务比较了解。防御这种CC攻击最好的方法就是及时修复对应漏洞了。




CC攻击防御

CC攻击的防御可以从多方面入手。
建立多链路,实现双活机制,紧急时刻可以实现链路切换或者多链路分流提升整体承载能力。

  • 重要业务接入CDN,一定程度上可以提升承载能力。
  • 可以对网站进行动静分离,限制请求的大小。
  • 及时修复拒绝服务相关的漏洞。



除了上面罗列的,最主要的就是依靠WAF进行监控及阻断了。对于大频率CC攻击,可以根据IP访问频率、UA特征、请求URL特征来识别。这需要十分熟悉自己的业务,比如正常访问情况下,单个IP的访问频率及后端响应时间在什么范围。有了这些数据,一旦遭到CC攻击就可以很快的发现。可以建立一套持续的CC攻击检测系统,从WAF层对业务的访问情况进行监控,确定日常访问的数据基线,发现异常后立即启动应急响应流程。


当然WAF层防御CC攻击也有一些其他的方案,比如为请求分配token,如果请求不包含这个token,返回一个302重定向并添加set cookie字段设置该token。如果客户端是一个正常的浏览器,就会解析set cookie添加该cookie,如果是机器人一般不会解析。同样的道理,也可以返回一个网页,在页面中嵌入JavaScript代码来设置Cookie并跳转。这种方案可以有效的识别机器流量,但是在实际落地的时候需要评估测试,比如有些企业的业务并不运行在浏览器端,某些场景下可能无法解析网页中的JavaScript代码或者返回的set cookie响应头,这时候可能会造成误拦截。

业内见诸报道的CC攻击并不多,更多的是其他形式的DDoS攻击,可能相对而言其他形式的DDoS攻击更容易实施吧。根据墨菲定律,该来的总会来的,所以还是要提前做好准备,以免被打个措手不及。


四、WAF踩坑系列

在过去的WAF的运营工作中,我们踩过不少坑,尤其是在WAF调优方面。有些问题正常情场景下不会出现,但是在线上某些特定场景下就会触发。


WAF性能优化相关

WAF一般采用NGINX、Tengine或者OpenResty等对流量进行转发。其中NGINX使用的是被动健康检查机制,由ngx_http_upstream_module实现,这个机制本身挺好的,但是如果相关参数配置不当,那么很容易发生问题。如下配置:

upstream xxx.xxx.com.cn { 
server 1.1.1.1 max_fails=3 fail_timeout=10s;
server 2.2.2.2 max_fails=3 fail_timeout=10s;
}

这里的max_fails=3 fail_timeout=10s代表:在10s的间隔内累计有3次请求失败(fail),那么NGINX就会认为对应的server在这10s内的时间内不可用。10s之后再重新尝试连接刚才不可用的server。这个健康检查机制是为了确保在后端服务器发生异常时,当前代理可以及时把请求转发到其他正常的后端服务器。NGINX官方文档对这两个参数的的默认配置为:max_fails=1 fail_timeout=10s。但实际线上的环境比较复杂,经常会出现后端响应慢等情况,建议在上线时把max_fails调大,fail_timeout调小,否则很容易出现因为后端响应慢使得WAF把所有后端服务器都摘掉,直接返回502的情况。

什么情况下会触发请求失败(fail)?这个由proxy_next_upstream来定义。proxy_next_upstream的默认配置为:error timeout。表示向后端转发时出现error或者timeout会触发请求失败。其他的可选配置项包括http_500、http_502、http_503、http_504等,分别代表后端返回500、502、503、或者504时就触发一次请求失败,这些配置项在使用的时候一定要慎重,建议只配置为error timeout。

此外,proxy_next_upstream对应的timeout,也会有几种不同的情况:

proxy_connect_timeout、proxy_send_timeout、proxy_read_timeout,分别代表当前代理在向后端代理转发请求时对应的连接、发送、读取超时时间,NGINX中这些参数的默认值都是60s。实际配置时可以参考整体链路不同代理层配置值,将WAF层配置的比后端服务器大一些。

以上是使用NGINX时被动健康检查配置的注意事项。Tengine本身使用的是主动健康检查,相对好用些。其他的还有很多的参数配置,比如CPU的分配(worker_process)、backlog参数、服务器系统层的参数等等,都要做一些优化,以提升WAF的处理性能。最好的方法就是---专业的人做专业的事---由运维架构师进行整体评估给出对应的参数,否则就只能通过压测来发现这些坑了。

WAF的运营免不了排查一些线上问题,了解NGINX或者Tengine的转发原理会很有帮助,其他的可以深入了解下HTTP协议,尤其是HTTP状态码及其含义等,比如:


301、302、304状态码的区别是什么?分别可能出现在哪些场景?
400状态码代表什么?什么情况下可能会出现400错误?
499状态码代表什么?什么情况下可能会触发499错误?
500代表什么?什么情况下可能会出现这种错误?
502代表什么?什么情况下可能会出现502?可能由哪些原因导致?
504代表什么?NGINX的哪些配置会和超时有关?


多层代理架构下真实IP的获取

在多层代理的场景下,我们碰到的另一个问题是:如何准确获取用户的真实IP?

以如下架构为例:


WAF可以直接识别到SLB层的IP,但是SLB层之前的IP,WAF是无法直接获取到的。如何获取用户真实IP,我们之前的方案是获取X-Forwarded-For(XFF)的第一个IP值。XFF的原理:每层代理在转发用户请求时,都会把上一层代理的IP追加到XFF头,然后向后转发。

比如CDN层在转发用户请求时,会把client的ip(1.1.1.1)添加到XFF头,然后转发给SLB。SLB在转发流量时会把CDN的ip(2.2.2.2)追加到XFF。这样WAF层接收到的请求中对应的XFF为:
X-Forwarded-For: 1.1.1.1, 2.2.2.2

因此可以通过获取XFF的第一个IP作为用户真实IP。但是这种方法存在一个缺陷:XFF值可以被伪造。攻击者可以通过伪造XFF头来误导WAF,比如用户在请求时就自己添加X-Forwarded-For: 8.8.8.8,因为一般的代理对XFF只会追加,不会覆盖,导致最终WAF层得到的XFF值为:
X-Forwarded-For: 8.8.8.8, 1.1.1.1, 2.2.2.2


此时获取XFF第一个IP作为用户IP,得到的就是8.8.8.8。

对应的优化方案有两种,第一种依然是通过XFF来获取,不过是获取倒数第n个IP,这样就不怕攻击者进行伪造XFF绕过了。这种方案在有些情况下也会出现些问题,比如某些请求在CDN层可能会经过不定次数的转发(尤其是经过海外的链路),同一个域名在WAF层的XFF IP数量并不一致,可能有两个IP的同时也存在三个IP。那么这种情况下到底以倒数第几个IP为准就有些难处理了。第二种方案,CDN厂商可以把他们识别的用户IP放到一个自定义的请求头,WAF层可以通过这些请求头的这些参数来获取真实用户IP,阿里CDN对应的自定义头为:Ali-CDN-Real-IP,网宿CDN对应的参数为Cdn-Src-Ip,有些CDN厂商也支持自定义添加对应的请求头,具体可和CDN厂商沟通确认。因为CDN前一层就是用户,所以这种方式获取到的真实IP比较准确,而且无法绕过。

准确获取用户真实访问IP是WAF进行准确拦截的基础。如果不能准确获真实访问IP,那么一方面攻击者可以利用这些缺陷绕过WAF的封禁,另一方面可能会出现WAF封禁掉正常的IP。


总结

在当今的Web攻防中,WAF依然发挥着很重要的作用,确保WAF的稳定高效对WAF的运营工作至关重要。当然这些也只是一个开始,还有更多的工作需要去完成。随着Web应用技术的发展,攻防形势在不断的变化,安全合规要求的提升、API接口防护、机器流量产业化、IPv6的推广等都对WAF提出了更多的要求,唯有提前布局,做好准备,才能在不断变化的攻防之中占据有利地势。(关于如何体系化的进行WAF运营,推荐阅读secsky大佬的:《体系化的WAF安全运营实践》)

以上就是我们在WAF方面的一些工作介绍,仅供大家参考。一家之言,难免疏漏,欢迎各位同仁指正。


参考资料

1、ModSecurity(https://www.modsecurity.org/)
2、从甲方的角度谈谈WAF测试方法(https://www.anquanke.com/post/id/84696)
3、CC攻击原理及防范方法(https://www.cnblogs.com/wpjamer/p/9030259.html)
4、 WEB应用防火墙测评基准 V1.0(http://www.owasp.org.cn/owasp-project/WebV1.pdf)
5、Magic Quadrant for Web Application Firewalls(https://www.gartner.com/en/documents/3964460/magic-quadrant-for-web-application-firewalls)
6、《2020国内WAF产品研究报告》(https://www.freebuf.com/articles/paper/226524.html)