点赞
评论
收藏
分享
举报
一文详解 WAF 如何与 Nginx T1K 深度融合,承载亿级流量
发表于2025-02-13 16:10

浏览 9.4k

作者:雷池引擎技术团队
文章来源:长亭科技


雷池(SafeLine)下一代Web应用防火墙,是长亭科技自主研发的、全球首款基于智能语义分析技术的WAF,它凭什么可以登顶 Github WAF 项目排行榜首位,收到热烈追捧?下面一文,向技术爱好者详细解析WAF 是如何通过融合 Nginx T1K 模块,承载海量 HTTP 请求。


我们将首先介绍雷池为什么使用 Nginx 作为底层流量转发引擎,然后再深入介绍 T1K 模块的核心工作原理,包括其背后的各种设计思想,最后再简单介绍雷池 Nginx 中其它有意思的特性。


1. 使用 Nginx 作为 WAF 流量转发引擎

从网络分层的角度来看,当 WAF 以反向代理部署时,可以将它看作一个 7 层设备:它接收网络中的 HTTP 请求,在完成流量检测之后再将请求转发给上游的业务服务器。所以抛开 WAF 的安全防护能力来说,WAF 其实就是一个 HTTP 反向代理设备。


Nginx 作为一款优秀的、久经考验的 HTTP 服务器/反向代理服务器,过去二十余年承载了 Internet 上海量 HTTP 请求的处理,许多大流量站点均使用 Nginx 作为其流量接入平台。Nginx 的高可靠性、高性能、丰富的可配置特性、模块扩展能力,是雷池选择 Nginx 作为流量转发引擎的主要原因。


下面我们简要回顾 Nginx 的几个核心设计,这也是 T1K 模块能够高效、稳定运行的基石。


1.1 master/worker 进程模型


Nginx 采用多进程模型,具体为 `单 master + 多 worker`。master 进程和 worker 进程的具体分工如下:


  • master 进程不需要处理网络事件,也不负责具体业务的执行。master 进程核心功能就是通过信号来管理 Worker 进程,从而实现配置更新、服务重启、平滑升级等功能
  • worker 进程才真正地处理业务请求,每个 worker 进程都是单线程的程序,它负责处理网络事件、定时器事件等



这种 `单 master + 多 worker` 的进程模型为 Nginx 提供了最基本的高可用、高性能、水平扩展能力:


  • 高可用:对 HTTP 请求的处理被限制在单个 worker 进程中,这使得单个 worker 进程的崩溃不会导致整个 Nginx 服务不可用。而且 master 进程可以通过监控 worker 子进程的异常退出,快速创建新的 worker 进程
  • 高性能:每个 worker 进程都是一个单线程程序,一个 HTTP 请求在其生命周期内只会被一个 worker 进程处理,这样避免了不同 worker 进程之间通信、临界区同步的开销
  • 水平扩展:可以自定义 worker 进程的个数。生产环境下一般会配置和 CPU 核心数相等的 worker 进程个数,并且配置 CPU 绑核,从而最大限度地利用多核 CPU 的并行能力,并减少进程间切换开销


1.2 事件驱动架构


一款高性能的网络服务器,通常要处理网络、磁盘、定时器等事件,Nginx 采用完全地事件驱动架构来处理业务,这是 Nginx 能够实现高并发、高吞吐的关键所在。


  • Nginx 的事件驱动框架负责网络、定时器等事件的收集、分发
  • 具体的业务模块作为事件消费者,需要提前注册自己感兴趣的事件
  • 当某类事件发生(例如最典型的是网络连接上的可读/可写事件)时,事件驱动框架会调用对应的事件消费者,此时业务模块才有机会得到执行
  • Nginx 的事件驱动框架会根据不同的操作系统选择最优的多路复用接口,例如在 Linux 中,默认使用 epoll


1.3 模块扩展能力


在 Nginx 中,几乎一切都是模块。Nginx 为`模块`定义了高度抽象的接口,即所有模块都遵 `ngx_module_t` 接口设计规范。对于 HTTP 请求的处理,Nginx 定义了一套完整的 HTTP 请求处理阶段,每个模块根据自己的需要,介入到 HTTP 请求处理的某个阶段。


Nginx 优秀的模块化设计保证了即使 Nginx 功能如此复杂,仍然能够保持清晰的代码结构。同时开发者可以实现自己的模块来对 Nginx 功能进行扩展,这也是雷池选择使用 Nginx 作为其流量转发引擎的主要原因之一。


2. 深度融合的黑魔法—— T1K


以上我们简要回顾了 Nginx 的几个核心设计,接下来我们正式介绍雷池 Nginx 中的 T1K 模块,T1K 模块的核心功能是将 Nginx 中的 HTTP 请求/响应发送给雷池的攻击检测引擎进行检测,然后再根据检测结果来决定该 HTTP 请求/响应在 Nginx 中的下一步处理流程。


因此,可以认为 T1K 模块充当了雷池流量转发引擎与攻击检测引擎之间的桥梁。


2.1 核心原理


准确来说,T1K 模块其实是一个统称,实际上它包含了一系列的 HTTP module,每个 module 都有明确的单一职责,共同完成 HTTP 请求/响应的检测。


如下展示了 T1K 模块的 HTTP 请求检测的流程:



  • 在 Nginx HTTP 请求处理流程的 access 阶段,实现请求检测功能。T1K 模块会产生一个 subrequest,该 subrequest 会重定向到一个特殊的、内部 location,通常命名为 @safeline
  • 该检测 subrequest 也会经历完整的 HTTP 请求处理流程,最终在 content 阶段被 `@safeline` location 的 handler 所处理
  • 该 handler 在处理 subrequest 时,会使用 Nginx 的 upstream 机制来和雷池检测引擎建立连接,并将待检测的内容发送给检测引擎
  • 解析检测引擎返回的检测结果,子请求处理结束
  • 原始请求恢复执行流程,T1K 根据检测结果来决定是返回 403 拦截页面,还是将该请求放行到下一阶段处理


如下展示了 T1K 模块的 HTTP 响应检测的流程:



  • 对 HTTP 响应的检测则是通过 HTTP 过滤模块实现,在 HTTP 响应的过滤链中,T1K 模块注册了自己的一个 HTTP 响应过滤模块
  • 在 T1K 过滤模块的 header_filter/body_filter 函数,T1K 模块仍然会产生一个 subrequest,该 subrequest 会重定向到一个名为 @safelinex 的内部 location
  • 该响应检测 subrequest 也会经历完整的 HTTP 请求处理流程,最终在 content 阶段被 `@safelinex` location 的 handler 所处理
  • 该 handler 在处理 subrequest 时,会使用 Nginx 的 upstream 机制来和雷池检测引擎建立连接,并将待检测的内容发送给检测引擎
  • 解析检测引擎返回的检测结果,子请求处理结束
  • 原始 HTTP 请求的响应过滤流程继续执行,T1K 根据检测结果来决定是返回 403 拦截页面,还是将响应 header/body 放行到下一个 HTTP 过滤模块处理


2.2 稳定可靠


不同于以旁路阻断模式运行的安全设备,当 WAF 以代理模式部署在 HTTP 流量的转发路径上时,WAF 承载的是实时业务流量,这对 WAF 的稳定性提出了极高的要求。


雷池转发与检测分离的架构,本身就为 WAF 的流量转发提供了基本的可靠性。Nginx 与检测引擎的进程隔离,保证了即使检测引擎出现异常,也不影响 Nginx 的正常执行。


除此之外,T1K 模块在与检测服务器通信时,设置了多种超时保护机制,例如连接建立超时、检测请求发送超时、检测响应读取超时等等,这些超时机制使得在高并发、大流量场景下,Nginx HTTP 请求的处理时延保持在可控的范围内。这些超时机制可以认为是 T1K 模块对其所依赖的上游检测服务的调用保护措施。


T1K 模块还实现了一种自适应检测限流算法,可以将它理解为 T1K 模块自身的一种服务降级机制。该算法可以根据 Nginx 的某些系统指标数据(例如 CPU 使用率)实时调整 HTTP 请求的检测率:


  • 当系统指标低于指定阈值时,T1K 模块会尽量实现 HTTP 流量的 100% 检测
  • 当系统指标超过指定阈值时,T1K 模块会通过降低 HTTP 请求的检测率来尝试将该系统指标维持到指定阈值之下


2.3 极致性能


从上述 T1K 模块的请求/检测流程的实现原理中,我们可以看到,T1K 模块是按照标准方式介入到 HTTP 请求处理流程中,而且在处理函数的代码实现中,不会引入任何阻塞行为。这就保证了加载 T1K 模块后,Nginx 的事件驱动框架依然能够按照预期工作,保证了 Nginx 的高性能、高吞吐。


另外,T1K 模块与雷池攻击检测引擎之间通过一种称为 `T1K 协议` 的私有协议进行通信,`T1K 协议` 采用 TLV 格式进行协议编码,在保证了协议可扩展的同时,提高了协议的信息携带量,网络通信效率得到了提升。


2.4 Lua 可编程


T1K 模块是 C 语言开发的 Nginx http 模块,为了支持某些用户的灵活需求,T1K 模块提供了 lua 可编程能力。T1K 模块在其执行过程中暴露了若干 hook 点,同时提供了若干 Lua API,使得我们可以为 T1K 模块编写 Lua 代码,从而控制 T1K 模块的行为。


例如,如下实例使用了 T1K 模块的 Lua 可编程能力,实现了对 POST HTTP 请求直接放行,而 GET 等其他方法的 HTTP 请求则正常检测:



2.5 可运维性


T1K 模块提供了丰富的配置指令,用于控制 T1K 模块的各种行为,举个例子,为了让用户配置是否需要对 HTTP 请求进行检测,T1K 模块在多种维度提供相应的配置方法:


  • 通过 `T1K_intercept` 指令,可以在全局、server 、location 不同级别配置是否开启检测
  • 通过 `T1K_ignore_with_header` 指令,可以配置当 HTTP 请求携带了某些指定头部时,对请求不检测
  • 通过 `T1K_no_intercept` 指令,可以基于特定变量的值来确定是否对请求进行检测


T1K 模块还内置了许多变量,通过这些变量可以获取到 T1K 的内部运行状态,例如请求/响应的检测结果、检测耗时等等。这些变量满足了用户的运维需求:


  • 通过在 access log 中使用这些变量,可以为问题排查提供线索
  • 结合使用 `nginx-module-vts`、`ngx_http_reqstat` 等第三方模块,可以实现对 T1K 指标数据的监测


除了满足观测需求外,T1K 变量还有些妙用。例如有用户基于我们的 T1K 模块开发自己的 lua 插件,在他们的插件代码中,通过 T1K 变量来判断 HTTP 请求是否被拦截,之后再执行自己的业务逻辑,例如发送告警信息等等。


2.6 广泛兼容


我们知道,Nginx 的模块化机制使得我们可以根据实际需要使能或关闭特定的模块,这些模块可以是 Nginx 的原生模块,也可以是自己或社区开发的第三方模块。因此,不同客户生产环境中运行的 Nginx 其实是千差万别的。经常有客户担心,T1K 模块能否在他们的环境中稳定运行,会不会与其他 Nginx 模块产生冲突?


得益于对 Nginx 架构原理、源码实现的深刻理解,T1K 模块虽然是长亭开发的一个第三方 Nginx 模块,但它的指令设计、配置解析、请求介入处理、变量支持等实现完全遵循 Nginx 的模块开发规范。这使得 T1K 如同一个 Nginx 原生模块一般,能够良好地运行在 Nginx 生态的各个实现上,包括但不限于 Nginx、Tengine、OpenResty、Ingress-nginx、Kong、Apisix。甚至在某些客户的 Nginx 私有实现版本上,T1K 模块也能够稳定运行,体现出了极佳的兼容性。


3. 1-∞,流式检测技术突破边界


除了 T1K 模块之外,雷池 Nginx 还实现了一些有意思的特性,用于满足我们客户多样化的需求,适配各种业务场景。


我们知道,Nginx 除了支持 HTTP 反向代理外,还支持四层代理,即我们所说的 Nginx stream。但是 Nginx 的实现存在一个限制,一个 tcp 端点无法同时工作在四层和七层上,即某个 `IP:Port` 要么是作为 HTTP server 来监听,要么是通过 Stream server 来监听,两者无法同时工作。雷池 Nginx 实现了一种 dispatch 机制,可以让一个 tcp 端点同时工作在 HTTP 和 Stream 上,并自动根据流量特征来决定某个 tcp 连接后面是交给 Nginx 的 HTTP 还是 Stream 来处理。


不久前我们发布了雷池 30,其中一个特性就是 `流式检测能力`。该特性就依赖了雷池 Nginx 所开发的流式处理能力,可以实现对请求 body 的 `边检测、边转发`,降低了 HTTP 请求的处理时延。


4. 结语


本文较为深入地介绍了雷池是如何通过 T1K 模块实现对 HTTP 流量的检测,介绍了 T1K 模块的核心流程、背后的各种设计考虑等。


`雷池引擎技术团队` 负责了雷池流量转发引擎、攻击检测引擎等核心模块的开发维护、技术创新工作,多年的研发投入使得我们在 Nginx 领域积累了丰富的经验。秉承着 `得益于社区、回馈于社区` 的开放理念,我们在两年前就开源了 `T1K 模块` 的 Lua 实现。未来我们团队仍将在 Nginx 等网关领域不断探索与创新,同时持续为大家分享我们对 Nginx 架构原理、模块开发的理解和经验。



已修改于2025-02-13 16:18
本作品系原创
创作不易,留下一份鼓励
NGINX官方账号

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
NGINX官方账号
这家伙很懒还未留下介绍~
331
文章
21
问答
201
粉丝
相关文章
概述 Nginx 从 1.9.0 开始加入了 stream 模块支持四层的代理,转发和负载均衡。但是,stream 模块的功能相对简单。对需要 ALG 处理的协议比如 FTP 的支持也远远不够。我试着去修改了 Nginx 的源代码,添加了alg模块。使之支持了 FTP主动模式和被动模式下的 ALG 功能。 Github 的源码地址为 : https://github.com/pei-jikui/nginx-alg。代码本身不困难,困难的是如何把代码模块化,有机地融入nginx原有的框架结构中,尽量少地修改已有的框架代码。而后者,需要对stream模块乃至nginx本身的框架和代码有一定的熟悉程度。图 1:FTP被动模式 数据连接 图2 :FTP主动模式 数据连接可能大家会说,Passive 模式不需要ALG 。准确
点赞 6
浏览 12.5k
原文来自:https://www.nginx.com/blog/nginx-app-protect-1-0-released/进行数字化转型的公司有明确的业务需求。其中包括改善现代业务应用程序的客户体验,采用敏捷实践以超越市场竞争对手,以及利用市场优势来推动新的收入来源。支持这些工作的是新的应用程序体系结构,这些体系结构可提高开发效率并结合了容器,微服务和API。对于现代应用程序,敏捷性和上市时间至关重要。安全通常是次要的考虑因素,或者被完全忽略。为什么?传统应用程序的安全控制并不总是能很好地映射到业务需求。例如,通常由SecOps团队配置和操作的那种复杂的Web应用程序防火墙(WAF)通常不太适合由DevOps团队支持特定业务线部署的敏捷应用程序。结果可能是安全性不足或配置错误,上市时间延迟以及不良的用户体验。推出NGINXAppProtectNGINXAppProtect是一种新的应用程序安全解决方案,它将先进的F5WAF技术的功效与NGINXPlus的敏捷性和性能相结合。该解决方案在NGINXPlus上本地运行,并解决了现代DevOps环境面临的一些最困难的挑战:将
点赞 4
浏览 8.9k
使用配置方式:install./configure--add-module={module_dir}&&make&&makeinstallconfserver{ listen80; client_max_body_size100m; location/{ roothtml/upload; } #Uploadformshouldbesubmittedtothislocation location/upload{ #Passalteredrequestbodytothislocation upload_pass/example.php; #Storefilestothisdirectory #Thedirectoryishashed,subdirectories0123456789shouldexist
点赞 3
浏览 11.2k