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验证, 反爬虫, 可视化界面, 头部分析, 威胁情报, 子域名暴力破解, 安全引擎, 开发者工具, 恶意爬虫识别, 数据可视化, 机器人检测, 网络安全, 网络流量审计, 自动化检测, 请求拦截, 请求频率控制, 通知系统, 隐私保护