feat(waf): complete composable rule orchestration

Add the React Flow rule editor, ordered graph APIs and runtime DAG execution.\n\nPublish rules only on OpenResty reload and reconcile checksum-driven IP group snapshots in bounded shared memory.
This commit is contained in:
ryan
2026-07-13 14:16:55 +08:00
parent d36409fbf9
commit a1a997bcda
72 changed files with 5897 additions and 3080 deletions
+15 -166
View File
@@ -1,176 +1,25 @@
# WAF 安全防护使用
你会学到:OpenFlare 边缘 Web 应用防火墙 (WAF) 的工作原理、防护维度,如何管理与引用三类 IP 组(手动、订阅与基于 Expr 的自动 IP 组),配置防 CC 挑战(PoW 人机验证)与地域级拦截,以及如何在不 reload 进程的情况下实现 IP 组成员的秒级热更新。
OpenFlare WAF 使用可视化有向无环图编排规则。新建规则时只填写名称,系统创建默认的“开始 → 通过”图并进入编辑器。
---
## 节点与连线
## 核心概念
- **开始**:每条规则唯一,沿 `next` 进入图。
- **通过**:结束当前规则;若路由仍有后续规则则继续执行。
- **阻止**:立即按配置的状态码和 HTML 响应终止请求。
- **IP 匹配**:配置 IP、CIDR 或 IP 组,分别连接 `true`、`false`。
- **地域匹配**:按国家或地区代码分支;City MMDB 不可用时按未匹配处理。
- **PoW**:未完成挑战时接管请求,验证通过后沿 `next` 继续。
在配置安全策略前,你需要理解 WAF 的几个核心组成部分:
服务端会拒绝循环、悬空出口、不可达节点、重复端口连接和无效配置。保存时携带页面加载得到的 `revision`;发生 409 冲突时应重新加载,避免覆盖他人修改。
| 概念 | 说明 | 作用范围与生效方式 |
| --- | --- | --- |
| **WAF 规则组 (Rule Group)** | 安全规则的逻辑集合。包括:IP 黑白名单(直接录入或引用 IP 组)、国家/地区地域限制、防 CC 挑战(PoW)以及自定义拦截响应。 | 支持全局生效或绑定到单个/多个网站。**修改规则组定义必须发布并激活配置版本**。 |
| **IP 组 (IP Group)** | 存放单个 IP 或 CIDR 网段的列表容器。分为**手动**、**订阅**与**自动**三类。WAF 规则组可通过 ID 引用 IP 组。 | 属于动态资源。**IP 组成员的增减支持 WebSocket 秒级无缝热同步,无需 reload 进程**。 |
| **人机挑战 (CC PoW)** | 基于 Proof of Work (工作量证明) 的人机验证挑战。通过让浏览器计算特定难度的哈希碰撞,静默阻断恶意刷接口的自动化脚本与 Bot,保障正常用户体验。 | 位于规则组内的配置 Tab。**修改 PoW 参数必须发布并激活配置版本**。 |
## 绑定与生效
---
启用的全局规则固定最先执行;路由绑定的自定义规则严格按列表顺序执行。调整顺序后需要发布配置版本,规则拓扑才会随 OpenResty reload 生效。
## 推荐配置顺序
IP 组成员是动态资源。Agent 每 5 秒检查 checksum,变化后在 Worker 间更新内存快照,无需重新发布规则或 reload。手动、订阅与自动 IP 组均可被 IP 匹配节点引用。单次完整 IP 组运行时快照最多 20 MiB;超过上限时发布或同步会返回错误,并继续使用上一份有效快照。
配置网站的安全防护时,推荐按这个顺序进行:
> [!IMPORTANT]
> 从旧固定黑白名单/地域/PoW 表单升级时,规则图会重置为“开始 → 通过”,旧策略字段不会迁移。请在发布新版本前逐条重新编排并验证规则。
1. 进入左侧菜单 **「安全性」->「IP 组」**,创建所需的 **手动 IP 组** (如开发者白名单) 或 **自动 IP 组** (如根据 404 扫描自动封禁的 IP)。
2. 创建或编辑 **WAF 规则组**(菜单路径 **「安全性」->「WAF」**):
* 绑定需要引用或阻断的 IP 组。
* 配置国家或省份的地域黑白名单限制。
* (可选) 在 `PoW` 标签页配置人机挑战参数。
* 在 `拦截返回` 标签页设定自定义状态码(如 403, 418)和 HTML 拦截页。
3. 将规则组关联到对应的 **路由规则**(在 **「规则管理」** 页面编辑对应规则,并在「WAF」选项卡中勾选关联规则组)。
4. 发布并激活配置版本,使边缘节点 (Agent) 开始应用 WAF 规则过滤流量。
---
## 详细步骤指南
### 第一步:管理与配置 IP 组
IP 组是进行大批量 IP 过滤的基石。OpenFlare 提供了极富弹性的三类 IP 组:
#### 1. 手动 IP 组 (Manual)
* **用途**:静态维护一些确定受信任或确定需长期拦截的 IP/网段。
* **配置**:点击「创建 IP 组」-> 类型选择「手动」-> 按行直接填入 IP 或 CIDR 格式(例如 `192.168.1.100` 或 `10.0.0.0/24`)。
#### 2. 订阅 IP 组 (Subscription)
* **用途**:接入第三方开源威胁情报库、云厂商公布的官方网段(如 Cloudflare, GitHub Action IP 列表),或团队内部统一维护的动态 IP 源。
* **配置参数**:
* **订阅 URL**:必须是合法的 `http` 或 `https` 链接。
* **订阅格式**:支持 `Text` 与 `JSON` 两种数据格式:
* **Text 格式**:纯文本格式。按行分隔读取 IP/CIDR,会自动过滤掉以 `#` 开头的注释行和空白行。
* **JSON 格式**:当订阅源是一个结构化的 JSON 响应时,需要编写 **映射规则 (Mapping Rule)** 从 JSON 数据中提取 IP 列表。
* **映射规则**:使用类似 JSONPath 的轻量点语法定位 IP 数组,支持以 `[]` 展开数组。例如:
* 若 JSON 结构为 `{"data": {"ips": ["1.1.1.1", "2.2.2.2"]}}`,则映射规则填写 `$.data.ips[]`(或 `data.ips[]`)。
* 若 JSON 根节点本身即为字符串数组(如 `["1.1.1.1", "2.2.2.2"]`),映射规则留空或填写 `$` 即可。
* **同步间隔 (分钟)**:该订阅组自动同步的周期,默认为 `1440` 分钟(24小时),允许范围为 `5` 至 `43200` 分钟。
* **安全限额与同步频率**:
* 为防止恶意或超大订阅源造成系统负担,单次抓取上限限制为 **2 MiB**,网络拉取超时为 15 秒。
* Server 默认每 5 分钟在后台扫描一次到期的订阅 IP 组并拉取同步。
> [!TIP]
> 关于 WAF 的动态 IP 组异步差分同步模型(WebSocket 实时热同步、不触发 Nginx Reload 机制)以及高性能 Lua 缓存方案等底层设计细节,请参阅 [WAF 设计](../design/waf-design.md)。
#### 3. 自动 IP 组 (Automatic)
* **用途**:**最具杀伤力的防扫描、防爆破自动通道**。
* **配置**:类型选择「自动」-> 编写 Expr 日志聚合逻辑。你可以直接引用系统内置的预设:
* **单 IP 404 高频扫描**:`request_count > 100 && StatusRatio(404) >= 0.8` (单个 IP 最近一小时请求超 100 次且 404 响应占比超 80%)。
* **单 IP 直连访问异常**:`ip_host_count > 50 && ip_host_ratio > 0.5` (绕过域名直接通过 IP 地址进行高频请求)。
* **测试与立即执行**:保存前可点击 **「测试规则」** 按钮预览当前日志窗口被命中的 IP。保存后可点击 **「立即执行」** 直接聚合日志并生成封禁名单。
> [!TIP]
> 自动 IP 组的详细语法和可用指标请参阅 [WAF 自动 IP 组规则语法](./waf-ip-group-expr.md)。
---
### 第二步:创建与配置 WAF 规则组
1. 导航至左侧菜单 **「安全性」->「WAF」**,点击 **「创建规则组」**。
2. 填写规则组名称(如 `production-api-shield`),选择是否为「全局规则组」。
3. 进入规则组详情,在下方几个配置 Tab 中依次设置:
#### 1. 黑白名单配置 (Allow / Block Lists)
* **直录 IP**:可直接在框内按行填入临时需要白名单放行或黑名单阻断的单个 IP 或网段。
* **IP 组引用**:点击「绑定 IP 组」,选择你在第一步中配置好的手动、自动或订阅 IP 组。白名单引用会直接放行,黑名单引用则直接阻断。
#### 2. 地域限制 (GeoIP)
* **说明**:OpenFlare 集成了 GeoIP 地理位置解析。
* **配置**:可开启地域限制开关,模式可选择「仅允许」或「禁止」。
* * 例如,若你的服务只服务于国内,可以将模式设为「仅允许」,并在国家列表中勾选 `中国`。
* * 支持细化到具体省份/地区(Region),一键拦截特定地理区域的恶意流量。
#### 3. 人机挑战配置 (PoW CC 防护)
* **说明**:开启防 CC 的人机挑战。当请求触发防CC机制时,浏览器会渲染一个静默挑战页面,并在几百毫秒内完成数学计算(哈希碰撞)。通过后会被写入 Cookie,后续访问直接放行。此过程对真实用户几乎无感,但能完美拦截不支持 JS/不具备计算能力的爆破脚本与 CC 僵尸工具。
* **核心参数**:
* **开启状态**:启用/禁用。
* **哈希难度**:控制碰撞难度(建议设定为 `4` 或 `5`)。
* **Cookie 有效期**:挑战通过后,在多长时间内免验证(例如 `3600` 秒)。
* **自定义挑战 HTML**:可定制挑战中的 Loading 页面风格,让其融入你的业务设计。
#### 4. 拦截返回 (Block Response)
* **说明**:设定 WAF 规则拦截恶意请求时的返回行为。
* **配置**:
* **拦截状态码**:可自定义拦截响应的 HTTP 状态码,例如标准的 `403`,或带有趣味性质的 `418 (I'm a teapot)`。
* **拦截响应体**:可在此输入自定义的 HTML 内容,展示给被拦截的攻击者(如:“WAF 拦截:你的请求已被记录”)。
---
### 第三步:将规则组关联到路由规则
规则组配置完成后,并不会自动生效,你需要将其与具体的路由规则绑定。
* **关联配置步骤**:进入 **「规则管理」** 页面,点击进入对应反代或静态托管规则的详情,切换到 **「WAF」** 选项卡,勾选并绑定刚才创建的 WAF 规则组。
> [!NOTE]
> 如果规则组被标记为 **「全局规则组 (is_global)」**,它将自动应用到网关上托管的**所有网站**,无需手动执行绑定。
---
### 第四步:发布并生效配置
1. 如果你修改了 **规则组定义**、**GeoIP 范围**、**PoW 防CC难度** 或 **网站的绑定关系**:
* 你需要点击管理端右上角的 **「配置预览」** -> **「发布并激活」**。
* Agent 拉取并校验新版本后,将重写本地 OpenResty 核心配置文件(`waf_config.json` 等)并平滑重载进程使策略生效。
2. 如果你只是更新了 **IP 组的成员名单**(如:在手动 IP 组中删减了一个 IP,或者自动 IP 组定时聚合出了一批新的封禁 IP):
* **不需要做任何发布操作!**
* Server 会在数据库更新后立即计算 IP 组全新的 Checksum 摘要。
* 控制面会通过 **WebSocket 长连接实时向所有在线的 Agent 广播** 变更的 IP 组成员,Agent 接收后会增量覆写到本地的运行时磁盘文件 `waf_ip_groups.json`。
* OpenResty Lua 引擎在处理新请求时,会在微秒级计算文件哈希,若发现 Checksum 变更则实时重载入内存字典(`ngx.shared`),**整个过程全程不需要 reload 任何 Nginx 服务,对线上高并发业务毫无影响**。
* 即使 WebSocket 连接意外中断,Agent 也会在每周期心跳中上报本地 Checksum,由 Server 差分补齐下发,确保万无一失。
---
## WAF 判定逻辑 (过滤漏斗)
当一个外部请求到达 OpenResty 数据面时,WAF 运行时引擎会以微秒级的极速开销进行如下判决流检测。只要判定出明确结果,即不再向下执行:
```text
请求进入 access 阶段
│
▼
获取当前请求绑定的所有规则组 (全局规则组 + 自定义规则组)
│
▼
1. 匹配 IP 白名单 / 白名单 IP 组? ──────(是)─────► [ 放行 (ALLOW) ]
│ (否)
▼
2. 匹配国家 / 省份地域白名单? ────────(是)─────► [ 放行 (ALLOW) ]
│ (否)
▼
3. 匹配 IP 黑名单 / 黑名单 IP 组? ──────(是)─────► [ 拦截 (BLOCK) ] ──► 返回自定义状态码与HTML拦截页
│ (否)
▼
4. 匹配国家 / 省份地域黑名单? ────────(是)─────► [ 拦截 (BLOCK) ] ──► 返回自定义状态码与HTML拦截页
│ (否)
▼
5. 该站点是否启用了 PoW CC 防护?
├───(是)───► [ 校验 PoW Cookie ] ──(验证通过)──► [ 放行 (ALLOW) ]
│ │
│ (未通过)
│ ▼
│ [ 渲染 PoW 挑战页 ] ──(计算正确)──► 写入 Cookie 并放行
▼
6. 未触发任何策略,属于正常业务流量 ───────────────► [ 放行 (ALLOW) ]
```
---
## 最佳实践与调优建议
* **白名单放行语义**:一旦某个生效规则组配置了 IP 白名单、白名单 IP 组或地域白名单,且请求命中了其中至少一条白名单规则,该请求将被直接放行,并优先绕过后续的黑名单与 PoW 检查;未命中的请求则会继续进行黑名单等后续防护校验。
* **白名单前置与保护**:在部署高强度黑名单或地域屏蔽前,建议首先创建一个「受信任 IP 组」,放入你团队的办公室出口 IP、本地开发 IP 以及可能访问你的第三方回调源站 IP(如微信、支付宝支付回调地址),并在规则组的**白名单**中优先引入。这可以有效防止误杀,确保信任的 IP 即使命中黑名单或 CC 限制也能无阻碍访问。
* **合理微调 PoW 难度**:人机 CC 挑战的哈希碰撞计算(`challenge_difficulty`)是一把双刃剑。
* 难度值 `3`:几乎瞬间完成计算,防 CC 强度低。
* 难度值 `4`:普通手机/低端浏览器在 100~300ms 内完成计算,防护性能良好。
* 难度值 `5`:需要 500ms~2s,防护性强,但低配端可能会感觉稍显卡顿。
* 难度值 `6` 及以上:计算量呈指数级上升,可能导致移动端用户浏览器 CPU 持续打满卡死。**因此强烈建议在生产环境选用 `4` 或 `5`**。
* **善用“测试规则”**:对于自动 IP 组,在点击保存之前务必点击 **「测试规则」**。通过分析当前窗口内被命中的 IP 列表,确认你的 Expr 表达式阈值(如请求数、404占比等)配置是否过宽或过紧,防止由于阈值配置不合理导致大面积误封正常用户。
* **分离静态与动态黑名单**:不要将需要长期封禁的静态恶意 IP 填入自动封禁组(因为自动聚合的名单随时会被新的执行窗口覆盖)。应该将确定的恶意 IP 录入到一个专门的「手动封禁 IP 组」中,并让规则组同时引用该手动组与自动组。
架构、图校验和失败回滚细节见 [WAF 可编排规则设计](../design/waf-orchestration-design.md)。