sebastianlutycz/lumina-waf
GitHub: sebastianlutycz/lumina-waf
LuminaWAF 是一个实验性的 AOT 编译、面向 SIMD 的 NGINX WAF 引擎,通过提前编译固定的 OWASP CRS PL2 策略来消除运行时规则解析开销,实现高性能请求检查。
Stars: 0 | Forks: 0
# LuminaWAF
**一个实验性的、AOT 编译、面向 SIMD 的 NGINX Web 应用防火墙引擎。**
LuminaWAF 探索了一个简单的问题:
LuminaWAF 将固定的入站 OWASP Core Rule Set paranoia level 2 策略所支持的语义转换为原生的执行单元。
生产请求路径不会解析 CRS 规则文件,不会加载正则表达式引擎,也不会动态解析外部的 SQL 注入分类器。
当前的发布版本线是 `v0.4.x`。
我独立花了几个月的时间构建它,主要是因为我喜欢深入到比合理范围更低的一层。
有时候构建某样东西的最好理由仅仅是:
## LuminaWAF 是什么
LuminaWAF 包含:
* 构建时策略转换器和实例化器;
* 生成的原生执行单元;
* 有界请求检查运行时;
* NGINX 动态模块;
* 正确性与性能的证据流水线。
LuminaWAF 没有在每个请求上解释规则文件,而是在构建时冻结支持的策略,并将其转换为:
* 生成的有限状态匹配器;
* 紧凑的候选路由器;
* 原生结构运算符;
* 有界转换流水线;
* 特定于架构的 SIMD 和标量执行路径。
在运行时,NGINX 将请求数据传递给生成的检查数据平面,并接收允许或阻止的决定以及匹配的规则元数据。
## 为什么存在
传统的 WAF 引擎提供高度动态的执行环境。这种灵活性可能会在请求路径中引入显著的工作量:
* 规则解析;
* 正则表达式分发;
* 动态转换流水线;
* 内存分配;
* 通用运算符路由;
* 重复的元数据查找。
LuminaWAF 采取了相反的方法:
1. 固定策略和来源溯源。
2. 验证支持的规则语义。
3. 提前编译策略。
4. 实例化原生执行代码。
5. 在调用者拥有的请求字节上执行生成的数据平面。
6. 保留已构建和已测量确切策略的证据。
该项目是一项关于以下方面的实验:
* 安全策略的提前编译;
* 面向 SIMD 的请求检查;
* 有界执行;
* 缓存感知的数据布局;
* 分支感知和无分支处理;
* 确定性内存所有权;
* 可重复的性能工程。
## 当前状态
当前版本通过生成的执行路径和原生执行路径的组合,支持固定的入站 OWASP CRS PL2 配置文件。
对 RC 前提交的内部非规范性确认确立了:
* 在固定的 CRS 回归门中约 **99.75% 的总体一致性**;
* 独立的正确性、全事务、固定速率延迟、饱和度和 PMU 实验;
* 用于配对 NGINX 开销分解的基准测试流水线;
* 保留的原始 JSON、日志、直方图、哈希和有效性决定。
从当前 x86-64 RC 前版本线进行的连续两次诊断冒烟测试观察到:
* 对于直接完整的允许事务,中位数 CPU 时间分别为 **106.20 µs** 和 **107.42 µs**;
* 对于等效的 ModSecurity 边界为 **2.44 ms** 和 **2.47 ms**,这意味着在这些运行中 ModSecurity 使用了大约 **23 倍** 的 CPU 时间;
* 在最近一次运行中,对于已加载但禁用的 Lumina 模块上的生产 PL2 检查,在连接数分别为 1 和 10 时,配对的 NGINX 服务器 CPU/请求开销分别为 **170.82 µs** 和 **207.04 µs**。
直接的全事务 CPU 测量与集成的 NGINX 服务器 CPU/请求开销是不同的边界,不能相互替代。这些冒烟观察使用了一个独立的基准测试过程和一次 E2E 重复,因此它们是诊断性的,而不是发布声明,并且不提供过程级别的置信区间。
这些数字并不是通用的性能声明。
它们仅适用于确切的:
* LuminaWAF commit;
* CRS 源 commit;
* 有序的 include manifest;
* 工作负载哈希;
* 引擎配置;
* 硬件配置文件;
* 测量边界;
* 鉴定类别。
RC 前的确认和冒烟观察都不是 `v0.4.0-rc.4` 的发布结果。它们是在没有完整内核 CPU 隔离的共享 Intel Haswell 主机上收集的。最终报告必须从确切标记的源状态重新生成,并且除非每个规范主机门都通过,否则将保持 `NON-CANONICAL`(非规范性)状态。
参见:
* [LuminaWAF Benchmark Harness v1](bench/benchmark_harness/README.md)
* [Benchmark methodology](methodology/README.md)
* [Published evidence contract](reports/README.md)
## 运行时设计
生产检查路径遵循以下规则:
* 支持的入站 CRS PL2 语义的 AOT 执行。
* 无运行时解析 CRS `.conf` 文件。
* 无动态加载的正则表达式引擎。
* 无动态加载的 SQL 注入分类器。
* 请求检查热路径中无堆分配。
* 调用者拥有的请求字节。
* 有界的线程局部转换存储。
* 生成的有限状态匹配器和路由表。
* 原生结构和转换运算符。
* 集成的、零分配的 SQL 注入分词器。
**零第三方运行时依赖。** 当前的 x86-64 `libluminawaf.so` 在其 `DT_NEEDED` 表中仅需要平台 C 运行时和 ELF 加载器。加载器提供有界线程局部转换存储使用的 TLS 解析器。核心库在运行时不需要正则表达式引擎、外部 SQL 分类器或其他 WAF 库。
NGINX、基准测试比较器、生成器和构建工具是开发或集成依赖项。它们不是核心检查库的运行时依赖项。
## 执行模型
```
pinned OWASP CRS policy
│
▼
manifest and semantic inventory
│
▼
AOT translator and materializer
│
▼
generated matchers, routers and native operators
│
▼
libluminawaf.so
│
▼
NGINX request adapter
│
▼
allow / block decision and matched-rule metadata
```
生成的执行单元计数与 CRS 源规则计数不是一一映射的。
设置规则、链、元数据和不携带分数的规则可能会被合并,或者由共享的原生执行来表示。
因此,兼容性是通过固定的清单和回归预言机建立的,而不是通过将生成的执行单元计数除以源规则计数来建立的。
## 兼容性范围
当前版本的精确兼容性声明是:
兼容性是使用兼容 ModSecurity 的预期,针对固定的 CRS PL2 回归套件进行验证的。
LuminaWAF 目前不声称:
* 支持每个 ModSecurity 指令;
* 支持任意用户提供的 `.conf` 文件;
* 完整的 CRS PL3 或 PL4 支持;
* 与 ModSecurity 运行时的逐字节等价性;
* 生产安全认证;
* 在每个处理器或工作负载上的普遍优越性;
* 与每个现有 ModSecurity 部署的直接替换兼容性。
确切支持的边界由以下各项定义:
* 固定的 CRS commit;
* 有序的 include manifest;
* 生成的策略清单;
* 工作负载哈希;
* 结构化的正确性产物;
* 保留的基准测试证据。
## 支持的架构
### x86-64
`v0.4` 版本基线需要:
* AVX2;
* BMI1;
* POPCNT。
CMake 默认不启用 `-march=native`。
本地主机构建可以选择使用:
```
-DLUMINA_NATIVE_TUNING=ON
```
原生调优的二进制文件不是可移植的发布产物。
### AArch64
在 `v0.4` 中,AArch64 支持是实验性的且不完整。存在部分标量和 NEON 路径,但完整的生成运行时和 NGINX 集成尚未通过原生发布验证。官方的 AArch64 支持计划在未来的版本中提供。
## 构建核心库
### 前置条件
* 基于 x86-64 且支持 AVX2、BMI1 和 POPCNT 的 Linux
* CMake 3.20+
* Clang 或 GCC
* Python 3
* Git
OWASP CRS 规则和数据文件不直接在本仓库中分发。
固定的 CRS 源作为 Git 子模块获取。实例化器将生成的 AOT 源写入被忽略的本地路径中。
```
git clone https://github.com/sebastianlutycz/lumina-waf.git
cd lumina-waf
git submodule update --init tests/eval_suite/coreruleset
./bench/benchmark_harness/materialize_runtime.sh
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release
cmake --build build \
-j"$(nproc)" \
--target luminawaf
```
生成的核心库是:
```
build/libluminawaf.so
```
标准的公开构建使用 CMake 选择的 C 编译器编译实例化生成的源码。它不使用预编译的解析器对象。
## NGINX 集成
针对目标环境中使用的确切 NGINX 版本构建模块。
模块构建期望核心库位于:
```
build/libluminawaf.so
```
示例:
```
LUMINA_ROOT="$(pwd)"
NGINX_SRC=/path/to/nginx-source
cmake -S "$LUMINA_ROOT" -B "$LUMINA_ROOT/build" \
-DCMAKE_BUILD_TYPE=Release
cmake --build "$LUMINA_ROOT/build" \
-j"$(nproc)" \
--target luminawaf
cd "$NGINX_SRC"
./configure \
--with-compat \
--add-dynamic-module="$LUMINA_ROOT/nginx_module"
make modules
```
加载生成的模块,并在需要的地方启用检查:
```
load_module /absolute/path/to/ngx_http_luminawaf_module.so;
events {}
http {
server {
listen 8080;
location / {
lumina_waf on;
root /srv/www;
}
}
}
```
将 `ngx_http_luminawaf_module.so` 及其匹配的 `libluminawaf.so` 打包在一起。
保留在模块构建期间选择的运行时库查找路径,并在激活前验证配置:
```
nginx -t
```
基准测试工具会生成并验证其自己固定的 NGINX 配置。
本仓库不提供特定于主机的生产配置。
## 可重复的基准测试
LuminaWAF Benchmark Harness v1 实现了归仓库所有的 V1.0 Protocol 证据流水线,用于 LuminaWAF `v0.4`。
完整的冒烟流水线可以通过全新的克隆启动:
```
./bench/benchmark_harness/run.sh smoke
```
启动器:
* 验证所需的主机命令;
* 初始化固定的 CRS 子模块;
* 下载确切的固定源版本和已验证的归档;
* 实例化 AOT 运行时;
* 构建固定的 NGINX 和 WAF 比较器;
* 构建 `wrk`、`wrk2` 和 Google Benchmark;
* 生成隔离的 NGINX 配置;
* 执行诊断证据流水线;
* 仅根据保留的产物生成 Markdown 报告。
引导程序安装到:
```
.cache/benchmark_harness_v1
```
它不会替换系统库或使用提升的权限安装软件包。
### 冒烟测试
```
./bench/benchmark_harness/run.sh smoke
```
`smoke` 验证完整的流水线。
它是诊断性的,不包含足够多的独立过程或请求样本以提供发布级别的置信区间或尾部延迟声明。
### 鉴定测试
```
LUMINA_BENCH_V1_HOST_PROFILE=shared-loaded-homelab \
LUMINA_BENCH_V1_HOST_NOTE='Background services remained active; this is not a canonical host.' \
./bench/benchmark_harness/run.sh qualification
```
`qualification` 执行发布规模的证据契约。
在共享或非隔离机器上进行的鉴定运行仍被明确标记为 `NON-CANONICAL`。
操作员注释永远不会将运行升级为规范状态。
### 规范测试
```
./bench/benchmark_harness/run.sh canonical
```
规范模式是失败即关闭的。
除了其他门控外,它还需要:
* 所有固定的基准测试比较器;
* 真实的固定 CRS PL2 策略;
* 完整的正确性门控;
* 五个独立的 Google Benchmark 进程;
* 每个进程保留十个原始内部重复;
* 内核隔离的基准测试 CPU;
* 不重叠的 SMT 同级线程放置;
* 每次重复至少 100,000 个接受的固定速率响应;
* 原始百分位数证据;
* 稳定的饱和点;
* 保留的编译器版本和有效的逐文件编译命令;
* 在测量之前捕获并在之后重新验证的完整产物和溯源哈希;
* 记录的 Lumina `DT_NEEDED` 集和干净的传统 SQL 分类器符号/重定位审计。
仅通过 `taskset` 设置亲和性是不够的。
规范模式验证每个声明的基准测试 CPU 是否被通过 sysfs 暴露的内核隔离 CPU 掩码所覆盖。
负载生成器 CPU 必须与服务器和微基准测试 CPU 不相交,包括 SMT 同级线程。
服务器和微基准测试 CPU 集可以重叠,因为它们的阶段是顺序执行的。
参见:
* [LuminaWAF Benchmark Harness v1](bench/benchmark_harness/README.md)
* [Normative methodology](methodology/README.md)
## 测量类别
V1.0 Protocol 有意将不同的测量边界分开。
### 正确性
正确性门控保留:
* 正向的阻止一致;
* 可观察到的确切匹配规则一致;
* 负向排除;
* 误报检查;
* 类别覆盖;
* 跳过;
* 超时;
* 异常;
* 分歧。
LuminaWAF 是根据兼容 ModSecurity 的固定预期进行评估的。
原生的 Coraza NGINX 连接器暴露了最终的 HTTP 判定,但不导出匹配的规则 ID。因此,其可观察到的契约被有意缩窄了。
NAXSI 作为原生 WAF 实现类参考被单独报告。它从不作为兼容 CRS 的引擎呈现。
### 全事务 CPU 时间
Google Benchmark 执行每个引擎暴露的完整入站事务生命周期。
这是一个进程内的 CPU 测量。
它不是 NGINX 的端到端请求延迟。
### 固定速率 E2E 延迟
`wrk2` 用于具有协调省略抗性的仅允许固定速率工作负载。
报告保留:
* p50;
* p90;
* p99;
* p99.9;
* 最大延迟;
* 原始直方图证据。
### 饱和度
闭环饱和度测量最大可持续吞吐量。
饱和产生的排队延迟永远不会被替代为服务延迟。
规范饱和点需要:
* 五次独立运行;
* 零响应错误;
* RPS 变异系数不大于 5%。
### 受控缩放
合成的规则数量实验与真实的 CRS PL2 比较隔离的,并始终标记为合成的。
### LuminaWAF 开销分解
该分解区分了:
* `E0`:普通的 NGINX;
* `E1`:带有 `lumina_waf off` 的相同 Lumina 模块;
* `E2`:生产 CRS PL2 检查。
报告在匹配的连接点上得出配对的服务器 CPU/请求差异。
它还包含以下内容的直接内核:
* 请求到束的投影;
* 预建束的检查;
* 完整的直接检查;
* 集成残差。
延迟百分位数仅作为绝对上下文显示,从不相减。
## PMU 诊断
合格的运行会收集允许事务的分组硬件性能计数器诊断:
* 每个事务的周期数;
* 每个事务的指令数;
* IPC;
* 分支未命中率;
* 通用缓存未命中率;
* L1 数据缓存未命中;
* LLC 未命中;
* 指令 TLB 未命中;
* 最低计数器运行百分比。
计数器的分子和分母对在单独的小型原子组中执行。
不受支持的缓存事件保持标记为 `unavailable`,而不会抑制受支持的 IPC 或分支指标。
直接的 `InspectPrebuilt` 和 `FullDirect` 内核接受相同的分组 PMU 处理。
PMU 结果是诊断性的,不被视作主要的请求延迟测量指标。
## 正确性与发布完整性
发布门控在固定的入站 CRS PL2 回归套件上,根据兼容 ModSecurity 的预期对 LuminaWAF 进行评估。
在接受发布之前,生成的源码漂移审计必须重现实例化的运行时。
清单和结构化的正确性产物定义了已测试的语义边界。
运行发布树验证门控:
```
python3 tools/verify_release_tree.py
```
被动的源码和二进制溯源标记记录在:
* [INTEGRITY.md](INTEGRITY.md)
性能结果只能与以下内容一起引用:
* 测量边界;
* 鉴定类别;
* 硬件配置文件;
* 工作负载哈希;
* 策略清单;
* 引擎配置;
* 样本量。
直接的引擎 CPU 时间、固定速率的 NGINX 延迟和 NGINX 饱和度是独立的声明。
`NON-CANONICAL` 结果必须保持如此标记。
冒烟测试结果是诊断性的。
## 安全
本项目处理恶意输入,应谨慎对待。
如果没有进行以下操作,请勿将 LuminaWAF 部署为生产安全边界:
* 审查源码;
* 重现生成的运行时;
* 运行完整的正确性门控;
* 验证目标 NGINX 构建;
* 针对预期的工作负载测试所选策略;
* 进行独立的安全审查。
应根据以下指南报告安全问题:
* [SECURITY.md](SECURITY.md)
在提供协调修复之前,请避免发布直接可利用的漏洞。
## 贡献
欢迎问题、技术批评和有针对性的 Pull Request。在贡献之前,请阅读:
* [CONTRIBUTING.md](CONTRIBUTING.md)
贡献契约涵盖 AOT 架构边界、所需的验证、基准证据、依赖策略和发布规则。
## 项目哲学
我不是安全供应商,也不是拥有 FAANG 规模硬件预算的研究团队。
我只是一个喜欢 C 语言、旧硬件、性能计数器,并且喜欢思考昂贵的抽象是否真的需要存在于热路径中的 homelabber。
构建 LuminaWAF 主要是为了乐趣、好奇心和学习。
欢迎技术批评。
请不要把我喷得太惨,但如果基准测试是错的,架构是有问题的,或者某个假设在现实中站不住脚,请开启一个 issue 并带上证据。
这就是这个项目的意义所在。
## 支线任务
这些是有趣的实验,理想情况下不允许阻塞主要版本的发布。
- [ ] 教 LuminaWAF 说 AVX-512
- [ ] 在比 Docker 首次发布还要年轻的硬件上运行它
- [ ] 在不意外购买另一台服务器的情况下验证 NEON 后端
- [ ] 在双插槽机器上测量 NUMA 扩展
- [ ] 添加一个 API 翻译层(SecLang -> C -> Atomic Flip,因为即使是 AOT 有时也需要倾听)
- [ ] 找出剩余的集成残差有多少是因为 NGINX 本身就是 NGINX
- [ ] 让基准测试工具在我意外尝试作弊时抱怨得更加激烈
## 许可
LuminaWAF 目前采用 GNU Affero General Public License v3.0 授权。
参见:
* [LICENSE](LICENSE)
`v0.4` 发布线仅提供 AGPLv3 许可证。
## 项目独立性
LuminaWAF 是一个独立的项目。
它不隶属于、也不受 OWASP Foundation 或 OWASP Core Rule Set 项目赞助或认可。
OWASP Core Rule Set 仍受其自身的许可证和项目政策管辖。
## 反馈
特别欢迎在以下领域提供反馈:
* AOT 规则翻译;
* 正确性方法论;
* NGINX 集成;
* 对抗性解析器行为;
* PMU 解释;
* 基准测试可重复性;
* NUMA 和多核扩展;
* SQL 注入分词;
* 较新的 x86 服务器硬件;
* AArch64 可移植性。
问题、可重现的反例和原始证据比仅基于主要数字的论点要有用得多。
如果这正是您的团队正在研究的工程问题,我也对系统、性能和研发工程机会持开放态度。
标签:Bash脚本, CISA项目, NGINX, OWASP CRS, SIMD, WAF, 编译器, 网络防火墙, 负责任AI, 逆向工具