zentinelproxy/zentinel-agent-bot-management
GitHub: zentinelproxy/zentinel-agent-bot-management
为 Zentinel 反向代理提供基于多引擎复合评分的机器人检测与管理能力,精准识别并处置自动化流量。
Stars: 1 | Forks: 0
# Zentinel Bot Management Agent
一个用于 [Zentinel](https://github.com/zentinelproxy/zentinel) 反向代理的机器人检测与管理代理。使用 **纯 Rust** 编写,结合四种检测引擎——头部分析、User-Agent 验证、已知机器人数据库(含反向 DNS 验证)和行为分析——为每个请求生成复合机器人分数(0-100),并作出 ALLOW、BLOCK 或 CHALLENGE 决策。
## 功能特性
### 检测引擎
- **头部分析** - 检查缺失的浏览器头部(`Accept`、`Accept-Language`、`Accept-Encoding`)、自动化工具标记(`X-Selenium`、`X-Puppeteer`、`X-Playwright`)、可疑头部值模式、现代 Chrome 的 `sec-ch-ua` 一致性,以及通用的 `Accept: */*` 检测
- **User-Agent 验证** - 匹配已知机器人关键词(curl、wget、python-requests、scrapy)、安全扫描器签名(sqlmap、nikto、nessus、nuclei、gobuster)、无头浏览器指示(HeadlessChrome、PhantomJS、Puppeteer、Playwright)、过时的浏览器版本、不可能的操作系统组合(Android + Windows、iPhone + Android),以及空/缺失的 User-Agent 字符串
- **已知机器人数据库** - 通过 User-Agent 模式识别“好机器人”(Googlebot、Bingbot、DuckDuckBot、Facebookbot、Twitterbot、LinkedInBot、Slackbot、UptimeRobot、Pingdom、StatusCake、Datadog)及其 IP 范围,并可选地使用正向确认反向 DNS(FCrDNS)进行验证。检测自称爬虫但 IP/DNS 验证失败的假机器人。同时匹配恶意模式数据库以识别安全扫描器(sqlmap、nikto、nessus、masscan、zgrab、nuclei、gobuster、dirbuster、wfuzz、hydra)和爬虫(scrapy、httrack)
- **行为分析** - 按 IP 跟踪会话随时间的变化:每分钟请求数(可配置阈值)、通过变异系数(CV)衡量的时间规律性(低 CV = 类似机器人的规律间隔)、路径多样性分析(唯一路径比例高 = 系统化爬取)以及持续的高请求速率
### 计分系统
每个检测引擎产生一个独立信号分数(0-100)。这些分数使用可配置的权重组合成最终加权分数(默认:头部 0.20、User-Agent 0.25、已知机器人 0.35、行为 0.20)。置信度根据可用信号的比例计算。
### 三向决策模型
| 分数范围 | 决策 | 动作 |
|----------|------|------|
| 0 -- 允许阈值(默认 30) | **Allow** | 请求通过并附带机器人分数字头 |
| 允许阈值 -- 阻断阈值 | **Challenge** | JavaScript 挑战、CAPTCHA 或工作量证明 |
| 阻断阈值(默认 80) -- 100 | **Block** | 返回 `{"error": "access_denied", "reason": "bot_detected"}` 的 403 响应 |
已验证的正常机器人(分数 0,置信度 1.0)始终被允许。已确认的假机器人(分数 100,置信度 1.0)始终被阻断。当置信度低于 `min_confidence`(默认 0.5)时,决策会被抑制。
### 挑战系统
- **JavaScript 挑战** - 重定向到可配置的 JS 挑战 URL,成功后在浏览器上设置一个 HMAC-SHA256 签名令牌 Cookie
- **CAPTCHA 挑战** - 重定向到验证码页面
- **工作量证明挑战** - 要求客户端解决一个可配置难度的计算难题
挑战令牌使用 HMAC-SHA256 签名,包含时间戳和随机数,并通过恒定时间比较进行验证以防止时序攻击。有效的令牌可在后续请求中绕过检测。
### 机器人分类
检测到的机器人被归类为:
| 类别 | 示例 |
|------|------|
| `human` | 真实浏览器流量 |
| `search_engine` | Googlebot、Bingbot、DuckDuckBot |
| `social_media` | Facebookbot、Twitterbot、LinkedInBot、Slackbot |
| `monitoring` | UptimeRobot、Pingdom、StatusCake、Datadog |
| `seo_tool` | Ahrefs、Semrush |
| `security_scanner` | sqlmap、nikto、nessus、nuclei |
| `malicious` | 假爬虫、暴力破解者 |
| `automation` | curl、wget、python-requests |
| `headless_browser` | Puppeteer、Selenium、Playwright、PhantomJS |
| `unknown` | 未分类 |
### 响应头部
每个响应都包含机器人元数据头部:
```
X-Bot-Score: 75
X-Bot-Category: automation
X-Bot-Confidence: 0.85
X-Bot-Verified: Googlebot # only for verified bots
X-Bot-Challenge: passed # only after challenge success
X-Bot-Signals: {"header_score":...} # only with debug_headers enabled
```
### 指标
该代理通过 v2 代理协议导出计数器和仪表盘指标:
| 指标 | 类型 | 描述 |
|------|------|------|
| `bot_management_requests_total` | counter | 总处理请求数 |
| `bot_management_requests_allowed` | counter | 允许的请求数 |
| `bot_management_requests_blocked` | counter | 阻断的请求数 |
| `bot_management_requests_challenged` | counter | 发送到挑战的请求数 |
| `bot_management_verified_good_bots` | counter | 已验证的正常爬虫 |
| `bot_management_verified_bad_bots` | counter | 检测到的假爬虫 |
| `bot_management_block_threshold` | gauge | 当前阻断阈值 |
| `bot_management_allow_threshold` | gauge | 当前允许阈值 |
## 安装
### 使用 Bundle(推荐)
```
# 仅安装此代理
zentinel bundle install bot-management
# 或安装所有捆绑代理
zentinel bundle install
```
该命令下载适用于你平台的正确二进制文件并将其放置在标准位置。详细信息请参见 [bundle 文档](https://zentinelproxy.io/docs/deployment/bundle/)。
### 使用 Cargo
```
cargo install zentinel-agent-bot-management
```
### 从源码编译
```
git clone https://github.com/zentinelproxy/zentinel-agent-bot-management
cd zentinel-agent-bot-management
cargo build --release
```
### Docker
```
docker run --rm \
-v /var/run/zentinel:/var/run/zentinel \
ghcr.io/zentinelproxy/zentinel-agent-bot-management:latest
```
## 快速启动
```
# 使用 Unix 套接字(默认)的基本用法
zentinel-bot-management-agent --socket /var/run/zentinel/bot-management.sock
# 使用 gRPC 传输
zentinel-bot-management-agent --grpc-address 127.0.0.1:50052
# 使用自定义配置文件
zentinel-bot-management-agent --socket /tmp/bot.sock --config bot-config.yaml
# 使用自定义机器人数据库
zentinel-bot-management-agent \
--socket /tmp/bot.sock \
--good-bots data/good_bots.json \
--bad-patterns data/bad_patterns.json
# 使用 JSON 结构化日志记录
zentinel-bot-management-agent --socket /tmp/bot.sock --json-logs --log-level debug
```
## 命令行选项
| 选项 | 默认值 | 描述 |
|------|---------|------|
| `--socket` / `-s` | `/tmp/zentinel-bot-management.sock` | 用于 UDS 传输的 Unix 套接字路径 |
| `--grpc-address` | - | gRPC 地址(例如 `127.0.0.1:50052`);会覆盖 UDS |
| `--config` / `-c` | - | YAML 或 JSON 配置文件的路径 |
| `--good-bots` | `data/good_bots.json` | 已知好机器人数据库路径 |
| `--bad-patterns` | `data/bad_patterns.json` | 恶意 User-Agent 模式数据库路径 |
| `--json-logs` | `false` | 启用结构化 JSON 日志 |
| `--log-level` | `info` | 日志级别:trace、debug、info、warn、error |
## 配置
配置通过 `--config` 传入的 YAML 或 JSON 文件加载。所有字段均为可选,未指定时回退到默认值。
### 完整 YAML 示例
```
# 决策的得分阈值
thresholds:
allow_threshold: 30 # Score at or below this = allow (0-100)
block_threshold: 80 # Score at or above this = block (0-100)
min_confidence: 0.5 # Minimum confidence to act on a score (0.0-1.0)
# 检测引擎开关和权重
detection:
header_analysis: true
user_agent_validation: true
known_bot_lookup: true
behavioral_analysis: true
weights:
header: 0.20
user_agent: 0.25
known_bot: 0.35 # Known bot database has highest weight
behavioral: 0.20
# 已知良好白名单机器人
allow_list:
search_engines: true # Google, Bing, DuckDuckGo
social_media: true # Facebook, Twitter, LinkedIn, Slack
monitoring: true # UptimeRobot, Pingdom, StatusCake, Datadog
seo_tools: false # Ahrefs, Semrush (off by default)
verify_identity: true # Reverse DNS verification for crawlers
custom_patterns: # Additional User-Agent patterns to allow
- "my-internal-bot/*"
custom_ip_ranges: # Additional IP ranges to allow (CIDR)
- "10.0.0.0/8"
# 挑战设置
challenge:
default_type: java_script # java_script, captcha, or proof_of_work
js_challenge_url: "/_zentinel/challenge.js"
challenge_url: null # URL for CAPTCHA challenges
token_validity_seconds: 300
token_secret: "change-me-in-production" # HMAC-SHA256 signing key
cookie_name: "_zentinel_bot_check"
# 行为分析调整
behavioral:
max_sessions: 100000 # Maximum concurrent IP sessions to track
session_timeout_seconds: 3600
rpm_threshold: 60 # Requests per minute before flagging
min_requests_for_scoring: 5 # Wait for N requests before scoring
max_request_history: 100 # Request timestamps to retain per session
# 缓存设置
cache:
verification_cache_size: 10000
verification_cache_ttl_seconds: 3600
dns_cache_size: 10000
dns_cache_ttl_seconds: 3600
# 性能
performance:
max_detection_time_ms: 50
adaptive_throttling: true
# 向响应添加 X-Bot-Signals 调试标头
debug_headers: false
```
### 最小配置
对于大多数部署,最小配置已足够,因为默认值较为合理:
```
thresholds:
block_threshold: 85
challenge:
token_secret: "your-secret-key-here"
```
## 已知机器人数据库
### 好机器人(`data/good_bots.json`)
一个 JSON 数组,包含机器人定义。每个条目包括名称、类别、User-Agent 模式、可选的 IP 范围(CIDR 表示法)以及可选的用于验证的反向 DNS 后缀:
```
[
{
"name": "Googlebot",
"category": "search_engine",
"ua_patterns": ["Googlebot", "Googlebot-Image", "Googlebot-Video"],
"ip_ranges": ["66.249.64.0/19", "64.233.160.0/19"],
"verify_dns": ".googlebot.com",
"is_good": true
}
]
```
当启用 `verify_identity` 时,代理会对带有 `verify_dns` 后缀的机器人执行两步验证:
1. 对客户端 IP 进行反向 DNS 查找以获取主机名
2. 对主机名进行正向 DNS 查找,确认其解析回客户端 IP
如果机器人自称是 Googlebot,但其 IP 未解析到 `*.googlebot.com`,则会被标记为假机器人,分数设为 100。
### 恶意模式(`data/bad_patterns.json`)
一个 JSON 数组,包含匹配恶意 User-Agent 字符串的正则表达式模式:
```
[
{
"pattern": "(?i)sqlmap",
"reason": "security_scanner_sqlmap",
"score": 95
},
{
"pattern": "(?i)hydra",
"reason": "brute_forcer_hydra",
"score": 95
}
]
```
## Zentinel 代理集成
在 Zentinel 代理配置中注册机器人管理代理:
```
agents {
agent "bot-management" {
type "custom"
unix-socket "/var/run/zentinel/bot-management.sock"
events "request_headers"
timeout-ms 50
failure-mode "open"
}
}
routes {
route "web" {
matches { path-prefix "/" }
upstream "backend"
agents "bot-management"
}
}
```
使用 gRPC 传输:
```
agents {
agent "bot-management" {
type "custom"
grpc "127.0.0.1:50052"
events "request_headers"
timeout-ms 50
failure-mode "open"
}
}
```
该代理使用 Zentinel 代理协议 v2 进行通信。它支持:
- **配置推送** - 在运行时从代理接收配置更新
- **指标导出** - 向代理报告计数器和仪表盘指标
- **健康报告** - 报告健康状态用于负载均衡和断路
- **取消** - 如果客户端断开连接,则取消进行中的检测
- **并发请求** - 最多同时处理 100 个请求检查
## 检测场景示例
### 场景 1:已验证的 Googlebot
请求到达,User-Agent 为 `Googlebot/2.1`,IP 为 `66.249.66.10`。
1. **头部分析**:缺失浏览器头部 -> 分数 45
2. **User-Agent 验证**:包含 "bot" 关键词 -> 分数 40
3. **已知机器人数据库**:匹配 Googlebot User-Agent 模式,IP 在 `66.249.64.0/19` 范围内 -> **已验证的正常机器人**
4. **结果**:分数 0,置信度 1.0,类别 `search_engine`,决策 **ALLOW**
已知机器人数据库会在机器人被验证时短路。请求通过并附带头部 `X-Bot-Score: 0` 和 `X-Bot-Verified: Googlebot`。
### 场景 2:假 Googlebot
请求到达,User-Agent 为 `Googlebot/2.1`,IP 为 `185.220.101.55`(非 Google IP)。
1. **已知机器人数据库**:匹配 Googlebot User-Agent 模式,但 IP 不在任何 Google CIDR 范围内。反向 DNS 未解析到 `*.googlebot.com` -> **检测到假机器人**
2. **结果**:分数 100,置信度 1.0,类别 `malicious`,决策 **BLOCK**(403)
### 场景 3:头less 浏览器爬虫
请求到达,User-Agent 为 `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 HeadlessChrome/120.0.0.0`,且缺少 `Accept-Language`、`Accept-Encoding` 和 `sec-ch-ua` 头部。
1. **头部分析**:缺失 accept-language(+15)、缺失 accept-encoding(+15)、声称 Chrome 120 但无 sec-ch-ua(+20) -> 分数 50
2. **User-Agent 验证**:包含 "headless" 关键词 -> 分数 60
3. **已知机器人数据库**:无匹配 -> 分数 50(中性)
4. **行为分析**:首次请求 -> 分数 50(数据不足)
5. **加权分数**:(50×0.20 + 60×0.25 + 50×0.35 + 50×0.20) / 1.0 = 52.5 -> **53**
6. **结果**:分数 53,置信度 1.0,类别 `headless_browser`,决策 **CHALLENGE**
客户端收到 JavaScript 挑战。如果成功解决并返回带有有效 `_zentinel_bot_check` Cookie 的请求,后续请求将被允许。
### 场景 4:激进爬取机器人
请求来自 `10.0.1.50`,User-Agent 为 `python-requests/2.28.0`。在过去一分钟内,该 IP 已发起 120 次请求,访问了 110 个唯一路径。
1. **头部分析**:缺失 accept、accept-language、accept-encoding -> 分数 45
2. **User-Agent 验证**:包含 "python-requests" 关键词 -> 分数 45
3. **已知机器人数据库**:无匹配 -> 分数 50
4. **行为分析**:RPM 120(阈值 60,+40 分)、路径多样性 0.92(+20 分) -> 分数 60
5. **加权分数**:(45×0.20 + 45×0.25 + 50×0.35 + 60×0.20) / 1.0 = 49.75 -> **50**
6. **结果**:分数 50,类别 `automation`,决策 **CHALLENGE**
如果爬虫未解决挑战继续请求,行为分数将持续上升,最终使整体分数超过阻断阈值。
### 场景 5:正常浏览器用户
请求到达,带有完整的 Chrome User-Agent,所有标准浏览器头部均存在,包括 `sec-ch-ua`、`Accept-Language: en-US,en;q=0.9` 和 `Accept-Encoding: gzip, deflate, br`。
1. **头部分析**:所有预期头部存在 -> 分数 0
2. **User-Agent 验证**:有效的现代 Chrome User-Agent -> 分数 0
3. **已知机器人数据库**:无匹配 -> 分数 50(中性)
4. **行为分析**:正常浏览模式,低 RPM,不规律间隔(高 CV) -> 分数 0
5. **加权分数**:(0×0.20 + 0×0.25 + 50×0.35 + 0×0.20) / 1.0 = 17.5 -> **18**
6. **结果**:分数 18,置信度 1.0,类别 `human`,决策 **ALLOW**
## 测试
```
# 单元测试
cargo test --lib
# 集成测试
cargo test --test integration
# 全部测试
cargo test
```
## 开发
```
# 带日志记录的调试构建
RUST_LOG=debug cargo run -- --socket /tmp/test.sock
# 发布构建
cargo build --release
# 检查格式
cargo fmt --check
# Lint
cargo clippy
```
## 架构
```
+-------------------------------------------------------------+
| Zentinel Proxy |
+--------------------------+----------------------------------+
| Unix Socket / gRPC
v
+-------------------------------------------------------------+
| Bot Management Agent |
| +---------------+ +----------------+ +-----------------+ |
| | Header | | User-Agent | | Known Bot | |
| | Analyzer | | Analyzer | | Database | |
| +-------+-------+ +-------+--------+ +--------+--------+ |
| | | | |
| +-------+------------------+--------+ | |
| | Score Calculator |<-----------+ |
| +---------------+------------------+ |
| | |
| +---------------v------------------+ |
| | Behavioral Analyzer | |
| +---------------+------------------+ |
| | |
| +---------------v------------------+ |
| | Decision Engine | |
| | (Allow / Challenge / Block) | |
| +---------------+------------------+ |
| | |
| +---------------v------------------+ |
| | Challenge Manager | |
| | (JS / CAPTCHA / Proof-of-Work) | |
| +----------------------------------+ |
+-------------------------------------------------------------+
```
## 许可证
Apache-2.0
## 贡献
欢迎贡献!请参考 [CONTRIBUTING.md](CONTRIBUTING.md) 获取指南。
## 安全
请将安全漏洞报告发送至 security@raskell.io。
标签:Bot管理, HTTP请求分析, Python工具, Rust, SEO防护, User-Agent校验, Zentinel, 代理防护, 反向DNS验证, 反爬虫, 可视化界面, 头部分析, 威胁情报, 子域名暴力破解, 安全引擎, 开发者工具, 恶意爬虫识别, 数据可视化, 机器人检测, 网络安全, 网络流量审计, 自动化检测, 请求拦截, 请求频率控制, 通知系统, 隐私保护