mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-03 15:06:36 +08:00
feat(waf): 新增 UA 检查节点 ua_check
支持要求携带 UA、浏览器/OS 白名单 and-or 匹配,以及优先屏蔽爬虫与非正常 UA。
This commit is contained in:
@@ -21,6 +21,10 @@ sidebar: false
|
||||
|
||||
## [unreleased]
|
||||
|
||||
### 新增
|
||||
|
||||
- WAF 规则编排新增「UA 检查」节点:可要求携带 User-Agent、按浏览器/操作系统白名单(且/或)匹配,并优先屏蔽常见爬虫与非正常 UA。
|
||||
|
||||
### 改进
|
||||
|
||||
- WAF 规则编辑器支持为节点自定义显示名称,并从节点库拖放到画布指定位置添加节点。
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
| 阻止 | 可创建多个 | 一个或多个 | 无 | HTTP 状态码、HTML 响应体 |
|
||||
| IP 匹配 | 可创建多个 | 一个或多个 | `true`、`false` | IP、CIDR、IP 组 ID |
|
||||
| 地域匹配 | 可创建多个 | 一个或多个 | `true`、`false` | 国家代码、地区代码 |
|
||||
| UA 检查 | 可创建多个 | 一个或多个 | `true`、`false` | 要求携带 UA、浏览器/OS 白名单与 and/or、屏蔽爬虫/非正常 UA |
|
||||
| PoW | 可创建多个 | 一个或多个 | `next` | 算法、难度、会话 TTL、挑战 TTL |
|
||||
|
||||
IP 匹配和地域匹配不区分黑名单或白名单。`true` 只表示请求匹配节点配置,`false` 只表示未匹配;放行或阻止的业务含义完全由连线决定。PoW 验证完成后沿 `next` 继续,未完成时由挑战页面接管当前请求,不产生 `false` 分支。
|
||||
IP 匹配、地域匹配与 UA 检查不区分黑名单或白名单。`true` 只表示请求通过该节点判定,`false` 只表示未通过;放行或阻止的业务含义完全由连线决定。UA 检查的求值顺序为:要求携带 UA → 屏蔽爬虫/非正常 UA → 白名单匹配。PoW 验证完成后沿 `next` 继续,未完成时由挑战页面接管当前请求,不产生 `false` 分支。
|
||||
|
||||
不在第一阶段实现循环、脚本节点、任意表达式节点、子图调用和跨规则跳转。
|
||||
|
||||
@@ -40,7 +41,7 @@ IP 匹配和地域匹配不区分黑名单或白名单。`true` 只表示请求
|
||||
* 图是有向无环图,禁止自环和任意循环。
|
||||
* 恰好存在一个开始节点和一个通过节点;阻止节点可以存在多个。
|
||||
* 开始节点无入边且恰好有一个 `next` 出口;通过和阻止节点无出口。
|
||||
* IP 匹配与地域匹配的 `true`、`false` 出口必须各连接一次;PoW 的 `next` 必须连接一次。
|
||||
* IP 匹配、地域匹配与 UA 检查的 `true`、`false` 出口必须各连接一次;PoW 的 `next` 必须连接一次。
|
||||
* 除终止节点外不得存在悬空出口;每个非开始节点至少有一条入边。
|
||||
* 所有节点都必须从开始节点可达,且从每个可执行节点出发都能抵达通过或阻止。
|
||||
* 边的源端口必须属于源节点类型;同一源端口不得连接多个目标。
|
||||
@@ -86,7 +87,7 @@ React Flow 编辑页采用全宽画布和固定右侧属性栏:
|
||||
|
||||
* 顶部提供返回、规则名称、启用状态、校验状态和保存操作。
|
||||
* 画布使用紧凑高度和较小的首次适配缩放,支持缩放、平移、框选、删除、自动布局和 MiniMap/Controls 等必要导航能力;节点拖动由 React Flow 本地受控状态实时处理,拖动结束后才把坐标写回编辑图。
|
||||
* “添加处理单元”提供 IP 匹配、地域匹配、PoW 和阻止;开始与通过由默认图提供且不可删除或重复添加。
|
||||
* “添加处理单元”提供 IP 匹配、地域匹配、UA 检查、PoW 和阻止;开始与通过由默认图提供且不可删除或重复添加。
|
||||
* 选中普通节点或连线后可使用画布删除按钮或 Delete/Backspace 删除;删除节点时同步移除关联连线。
|
||||
* 右侧属性栏默认隐藏,选中节点后才显示并用于编辑配置;点击连线或画布空白处时收起。
|
||||
* 地域匹配属性使用完整国家与 ISO 3166-2 一级行政区数据;国家选项同时显示本地化名称与代码,行政区支持按国家名、行政区名或代码搜索,避免一次渲染数千个选项。
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# WAF UA Check Node Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add WAF graph node `ua_check` (require UA, browser/OS whitelist with and/or, bot/abnormal blocks) end-to-end: validate/compile, Lua runtime, editor UI.
|
||||
|
||||
**Architecture:** Match-node pattern like `geo_match`. Control plane stores `UACheckConfig`; edge classifies `http_user_agent` with analytics-equivalent token rules; evaluation order: require → block bots → block abnormal → whitelist.
|
||||
|
||||
**Tech Stack:** Go (waf package), Lua (OpenResty waf_runtime), React/TS editor, Vitest, Go tests.
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-07-19-waf-ua-check-node-design.md`
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Type `ua_check`; handles `true`/`false`.
|
||||
- Config fields: `require_ua`, `browsers`, `operating_systems`, `match_mode` (`and`|`or`, default `or`), `block_common_bots`, `block_abnormal_ua`.
|
||||
- Closed enums for browser/OS labels matching analytics.
|
||||
- Block before whitelist; empty lists = no whitelist constraint.
|
||||
- No schema_version bump; no new HTTP API.
|
||||
- Changelog + Chinese design doc update.
|
||||
|
||||
## File Map
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `internal/apps/openflare/waf/graph_types.go` | Type + config |
|
||||
| `internal/apps/openflare/waf/graph_validate.go` | Validate + handles |
|
||||
| `internal/apps/openflare/waf/graph_compile.go` | Compile normalize |
|
||||
| `internal/apps/openflare/waf/*_test.go` | Go tests |
|
||||
| `internal/apps/agent/nginx/waf_runtime.lua` | Runtime eval |
|
||||
| `internal/apps/agent/nginx/waf_runtime_spec.lua` | Lua specs |
|
||||
| `internal/apps/agent/nginx/manager_test.go` | Embed smoke if needed |
|
||||
| Frontend editor components + types | UI |
|
||||
| `docs/design/waf-orchestration-design.md` | Node table |
|
||||
| `docs/changelog/index.md` | Unreleased |
|
||||
|
||||
### Task 1: Backend types/validate/compile
|
||||
### Task 2: Lua runtime + specs
|
||||
### Task 3: Frontend editor
|
||||
### Task 4: Docs + gates
|
||||
|
||||
(Detailed code follows during implementation; execute TDD per layer.)
|
||||
@@ -86,18 +86,21 @@
|
||||
2) browser, os := classify(ua)
|
||||
3) if block_common_bots and (browser == "Bot" or os == "Bot") → false
|
||||
4) if block_abnormal_ua and browser in {"Bot","Other","Unknown"} → false
|
||||
5) browser_ok := browsers 为空 or browser ∈ browsers
|
||||
os_ok := operating_systems 为空 or os ∈ operating_systems
|
||||
6) if browsers 与 operating_systems 皆空 → true
|
||||
7) if match_mode == "and" → browser_ok and os_ok
|
||||
if match_mode == "or" → browser_ok or os_ok
|
||||
5) has_browsers := browsers 非空; has_os := operating_systems 非空
|
||||
6) if not has_browsers and not has_os → true
|
||||
7) browser_hit := browser ∈ browsers; os_hit := os ∈ operating_systems
|
||||
8) if has_browsers and not has_os → browser_hit
|
||||
9) if has_os and not has_browsers → os_hit
|
||||
10) if both lists set:
|
||||
match_mode == "and" → browser_hit and os_hit
|
||||
match_mode == "or" → browser_hit or os_hit
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- **屏蔽优先于匹配**:步骤 3–4 在白名单之前。
|
||||
- **未配置匹配列表**:步骤 6 直接 true(仅受 require / block 约束)。
|
||||
- **仅一侧列表有值**:另一侧 `*_ok` 恒 true;`and`/`or` 结果等价于该侧是否命中。
|
||||
- **仅一侧列表有值**:只校验该侧是否命中;`match_mode` 仅在两侧都有值时生效。
|
||||
- 节点本身不 allow/block,仅选句柄;下游连线决定动作。
|
||||
|
||||
### 示例
|
||||
|
||||
Reference in New Issue
Block a user