Web 应用防火墙(Web Application Firewall,简称WAF)是针对 HTTP/HTTPS 流量进行安全防护的一种产品,简单来说,它可以对 HTTP/HTTPS 流量进行恶意特征识别、阻断攻击流量,并将过滤后的安全流量放行给上游业务服务器。WAF 通常支持多种部署模式,而在这些部署模式中,反向代理模式一直是一种比较受欢迎的模式,其部署方式如下:
可以看到,在反向代理模式下,WAF 接收来自 Internet 上的 HTTP 请求,在完成流量检测之后再将请求转发给上游的业务服务器。此时 WAF 对外的表现就是一个 Web 服务器,客户端不感知后端真实业务服务器的存在。由于所有 HTTP 流量都首先到达 WAF 进行处理,这就对 WAF 的 HTTP 流量处理性能有非常高的要求。
雷池的反向代理模式、透明代理模式都是通过 Nginx 来实现 HTTP 流量的代理转发。本文将对 Nginx 以及雷池对 Nginx 的使用进行简单介绍。
在 Nginx 官网 上是这样介绍 Nginx 的:
nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server.
可以看出,Nginx 提供了 HTTP 服务器/HTTP 反向代理、邮件代理、通用的 TCP/UDP 代理等功能。Nginx 最开始是由 Igor Sysoev 开发,目前已经被 F5 收购并推出了 Nginx 商业版本。虽然有了 Nginx 商业版本,但其开源版本仍保持活跃状态。根据 Netcraft 公司的最新报告,Nginx 在 Web 服务器领域仍然占据最大份额:
Nginx 作为一款优秀的、高性能的 Web 服务器,其在代码架构上有许多优秀的设计,接下来对这些设计进行简单介绍。
Nginx 采用多进程模型,具体为 「单 master + 多 worker」 。master 进程和 worker 进程的具体分工如下:
在网络领域,通常会有 「控制面」 和 「数据面」 的概念。从上面对 Nginx 进程模型的介绍可以看出,master 进程相当于 Nginx 的 「控制面」,不处理具体的业务请求,只专注于对 worker 的管理。当 worker 进程异常退出时,master 进程会立即创建新的 worker 进程,从而尽量减少对业务的影响。
而 worker 进程则相当于 Nginx 的 「数据面」 ,负责处理真实的业务请求。每个 worker 进程只有一个主线程,这样就避免了进程内多线程同步的开销。同时,一个 HTTP 请求在其生命周期内只会被一个 worker 进程处理,这样也避免了不同 worker 进程之间通信、数据同步的开销。
可以看到,Nginx 的 「master/worker」 进程模型是其高可靠、高性能的基石。
一款高性能的网络服务器,通常要处理网络、磁盘、定时器等事件,而这些事件中,最重要的就是网络 I/O 事件。在传统的网络编程领域,一些服务器会采用 「每连接一线程」 或 「每连接一进程」 网络 I/O 模型,在这些模型中,进程或线程是网络事件的消费者。而 Nginx 采用完全的事件驱动架构来处理业务,具体来说,具有以下特点:
Nginx 的事件驱动架构使得网络性能/吞吐量得到大幅提升,但这也对业务模块提出很高的要求,因为在它们的执行过程中,不能有阻塞行为,否则会导致导致其他事件得不到及时响应,最终降低整个 worker 进程的吞吐量。
在 Nginx 中,几乎一切都是模块。Nginx 为 「模块」 定义了高度抽象的接口,即所有模块都遵循 「ngx_module_t」 接口设计规范。同时,所有模块又是分层次、分类别的。如下对 Nginx 的模块设计进行简单介绍:
Nginx 优秀的模块化设计保证了即使 Nginx 功能如此复杂,仍然能够保持清晰的代码结构,同时也允许开发者根据模块接口开发自己的 Nginx 模块,从而对 Nginx 进行扩展。
作为高性能服务器的典范,Nginx 还有非常多的优秀设计,这里简单列举一些:
由于 Nginx 本身就是一款优秀的反向代理服务器,因此雷池使用 Nginx 作为 WAF 的流量转发引擎,实现 HTTP 流量的反向代理功能。但是 WAF 不仅仅需要对流量进行转发,其核心功能还是对流量进行检测。雷池在 Nginx 中自研了一个 HTTP 模块:t1k 模块,用于在 Nginx 中将接收到的流量发送给雷池的检测引擎,并根据检测引擎的返回结果来决定是直接返回 403 拦截,还是继续转发请求。
得益于 Nginx 的可定制化开发能力,在 Nginx 中实现上述功能并不复杂。雷池 t1k 的主要工作原理如下:
而正是得益于 Nginx 的高度可定制能力、动态模块加载能力,t1k 模块也可以嵌入到已有的 Nginx/OpenResty 服务器(包括以 OpenResty 为底座的 Kong、APISIX 等 API 网关产品中)中运行,这也是我们的 「嵌入式部署模式」。