Use full country and ISO subdivision data, show localized country names with codes, and add searchable region selection.
9.9 KiB
WAF 可编排规则设计
本文定义 OpenFlare WAF 从固定判定链重构为可视化有向无环图(DAG)的目标架构、数据模型、执行语义、发布模型与迁移边界。IP 组的来源与成员计算仍遵循 WAF 设计,本文只改变规则如何组合和执行。
目标与边界
用户新增 WAF 规则时只输入名称。Server 随即创建一张合法的默认图 开始 → 通过,前端进入基于 React Flow 的独立编排页面。用户通过添加处理单元、配置节点并连接分支构建策略,不再填写固定顺序的黑白名单与 PoW 表单。
第一阶段支持以下节点:
| 节点 | 数量约束 | 输入 | 输出 | 配置 |
|---|---|---|---|---|
| 开始 | 每张图恰好一个 | 无 | next |
无 |
| 通过 | 每张图恰好一个 | 一个或多个 | 无 | 无 |
| 阻止 | 可创建多个 | 一个或多个 | 无 | HTTP 状态码、HTML 响应体 |
| IP 匹配 | 可创建多个 | 一个或多个 | true、false |
IP、CIDR、IP 组 ID |
| 地域匹配 | 可创建多个 | 一个或多个 | true、false |
国家代码、地区代码 |
| PoW | 可创建多个 | 一个或多个 | next |
算法、难度、会话 TTL、挑战 TTL |
IP 匹配和地域匹配不区分黑名单或白名单。true 只表示请求匹配节点配置,false 只表示未匹配;放行或阻止的业务含义完全由连线决定。PoW 验证完成后沿 next 继续,未完成时由挑战页面接管当前请求,不产生 false 分支。
不在第一阶段实现循环、脚本节点、任意表达式节点、子图调用和跨规则跳转。
控制面架构
规则图采用控制面编辑态和数据面运行态分离的双模型:
- React Flow 编辑器提交版本化图 JSON,其中包含节点 ID、节点类型、显示名称、坐标、类型化配置和连线。
- Server 对整张图执行权威校验,通过后以单个事务保存图并递增修订号。
- 配置发布时,Server 再次校验所有启用规则,将图编译为不含坐标、标签等 UI 字段的紧凑运行时 DAG,并收集被引用的 IP 组 ID。
- Agent 原子落盘完整发布快照并 reload OpenResty。新 Worker 启动时只加载和解析一次规则 JSON。
- 请求热路径只遍历 Worker 内存中的不可变运行时图,不读取文件、不计算 checksum、不解析 JSON。
编辑态 JSON 使用明确的 schema_version。节点配置使用按节点类型区分的结构,不允许用无约束键值对象绕过 Server 校验。初始安全上限为每条规则 128 个节点、256 条边和 256 KiB 编辑态 JSON;这些限制由 API 和发布编译器共同执行。
图结构约束
规则保存与发布必须满足全部约束:
- 图是有向无环图,禁止自环和任意循环。
- 恰好存在一个开始节点和一个通过节点;阻止节点可以存在多个。
- 开始节点无入边且恰好有一个
next出口;通过和阻止节点无出口。 - IP 匹配与地域匹配的
true、false出口必须各连接一次;PoW 的next必须连接一次。 - 除终止节点外不得存在悬空出口;每个非开始节点至少有一条入边。
- 所有节点都必须从开始节点可达,且从每个可执行节点出发都能抵达通过或阻止。
- 边的源端口必须属于源节点类型;同一源端口不得连接多个目标。
- 节点 ID 在图内唯一,边 ID 在图内唯一,所有边引用的节点必须存在。
- 节点配置必须通过对应类型的字段、范围、引用存在性和体积校验。
前端提供即时校验和连线限制以改善体验,但 Server 是唯一权威校验方。删除节点时前端同步删除关联边并将规则标记为未保存;图恢复合法前禁止保存。
多规则执行语义
一个路由可以绑定多条自定义规则。绑定关系是有序列表,并遵循以下顺序:
- 启用的全局规则固定最先执行,不参与路由侧排序。
- 路由绑定的启用规则按绑定顺序依次执行。
- 当前规则抵达阻止节点时立即输出该节点配置的响应并终止请求。
- 当前规则抵达通过节点时,只表示当前规则执行完成;若仍有后续规则则继续执行。
- 全部规则均抵达通过节点后,请求才真正放行并进入后续 OpenResty/回源链路。
运行时图在发布前已经过完整校验。若 Lua 执行器仍遇到未知节点、未知端口、缺失目标或超过节点步数上限,则记录限频错误并阻止请求,避免损坏的安全配置意外放行。
IP 组内存刷新
规则拓扑只在发布并 reload OpenResty 时生效;IP 组成员仍可由手动、订阅或自动任务独立更新,不要求发布或 reload。
IP 组采用协调 Worker、共享快照和 Worker 本地对象的两级缓存:
- 请求始终读取当前 Worker 内存中的 IP 组对象,不访问文件或共享字典中的 JSON。
- 每 5 秒只有一个取得共享锁的 Worker 读取轻量 checksum 文件。
- checksum 未变化时立即结束,不读取完整
waf_ip_groups.json。 - checksum 变化时,协调 Worker 读取并验证一次完整 JSON,再把原始快照按 checksum 写入独立的 64 MiB
ngx.shared.openflare_waf_ip_groups,最后更新提交指针。 - 其他 Worker 发现共享版本变化后,从共享内存取得快照、解析并原子替换各自的本地对象,不重复读取磁盘。
- 刷新失败时继续使用上一份有效对象,限频记录错误,并在下一周期重试。
Agent 必须先原子替换 IP 组 JSON,最后原子更新 checksum,使 Worker 永远不会把半写入文件识别为新版本。Server 发布/同步和 Agent 落盘共同执行 20 MiB 聚合快照上限;共享字典使用不会强制淘汰旧键的安全写入,失败时保留当前与上一代不可变快照。
API 与编辑器
创建接口只接受规则名称,创建成功后返回带默认图的规则详情。规则元数据、图保存和路由绑定使用独立操作,避免修改启用状态或绑定时覆盖画布。
图详情包含 revision。保存请求提交 revision + graph,Server 仅在修订号匹配时更新并递增修订号;不匹配时返回冲突,前端提示重新加载,禁止静默覆盖其他页面的修改。路由绑定接口接受有序规则 ID 数组。
React Flow 编辑页采用全宽画布和固定右侧属性栏:
- 顶部提供返回、规则名称、启用状态、校验状态和保存操作。
- 画布使用紧凑高度和较小的首次适配缩放,支持缩放、平移、框选、删除、自动布局和 MiniMap/Controls 等必要导航能力;节点拖动由 React Flow 本地受控状态实时处理,拖动结束后才把坐标写回编辑图。
- “添加处理单元”提供 IP 匹配、地域匹配、PoW 和阻止;开始与通过由默认图提供且不可删除或重复添加。
- 选中普通节点或连线后可使用画布删除按钮或 Delete/Backspace 删除;删除节点时同步移除关联连线。
- 右侧属性栏默认隐藏,选中节点后才显示并用于编辑配置;点击连线或画布空白处时收起。
- 地域匹配属性使用完整国家与 ISO 3166-2 一级行政区数据;国家选项同时显示本地化名称与代码,行政区支持按国家名、行政区名或代码搜索,避免一次渲染数千个选项。
- 离开存在未保存变更的页面前必须提示;保存冲突和 Server 校验错误应定位到相关节点或边。
WAF 列表展示规则名称、启用状态、节点数量、应用路由数量和更新时间。新建规则的对话框只有名称字段,成功后立即导航到编排页面。
持久化与迁移
规则记录增加版本化图 JSON 与修订号;绑定记录增加执行顺序。图作为一个聚合整体保存,不拆成节点表和边表,以保证编辑操作的事务边界,并让新增节点类型不必频繁扩展数据库 Schema。
升级现有安装时:
- 保留规则名称、全局标记、启用状态及路由绑定关系。
- 所有规则图重置为
开始 → 通过,不迁移旧 IP/地域名单、PoW 或拦截响应配置。 - 现有绑定按稳定顺序写入顺序字段;全局规则仍固定前置。
- 新图和运行时稳定后移除旧规则字段、固定顺序编译逻辑和旧前端表单,不长期维护双执行器。
该迁移会让旧防护配置停止生效,升级说明必须显著提示管理员在发布下一版本前重新编排规则。
发布、失败与回滚
规则图只在配置发布时生效。发布前校验或编译失败时拒绝发布,当前活动版本保持不变。Agent 写入、OpenResty 配置检查或 reload 失败时,应用流程失败并恢复上一份有效发布版本。
新 Worker 只接受完整且可解析的规则运行态配置。旧 Worker 在 OpenResty 优雅 reload 期间继续使用旧内存图,新 Worker 使用新图,因此请求不会观察到半更新状态。
地域数据库不可用时,地域匹配返回 false 并限频告警,保持现有行为。IP 组刷新失败时保留旧内存快照。PoW 未完成由挑战模块接管请求,不视为执行错误。
测试与验收
- Go 单元测试覆盖图结构、端口、可达性、终止性、节点配置、体积限制、编译结果、修订冲突和绑定顺序。
- 数据库测试覆盖 PostgreSQL/SQLite 迁移、默认图、旧绑定稳定排序和回滚。
- Lua 测试覆盖所有节点出口、多规则顺序、全局规则前置、多个阻止响应、PoW 接管和损坏运行时图保护。
- Agent/OpenResty 测试覆盖发布 reload、加载一次、失败回滚、IP 组五秒 checksum 刷新和旧快照保留。
- 前端测试覆盖创建后导航、特殊节点唯一性、连线限制、属性编辑、即时校验、未保存提示和并发冲突。
- 集成测试从控制面创建并编排规则,发布后用真实请求验证放行、阻止、PoW 和 IP 组热刷新。
- API 变更后运行
make swagger;完成实现后运行前端检查与构建以及make code-check。