feralbureau/zerodrop
GitHub: feralbureau/zerodrop
一个基于 Caddy forward_auth 和 Redis 的自托管 Web 应用防火墙,提供多层请求过滤与实时仪表板管理。
Stars: 0 | Forks: 0

# ZeroDrop
### 你的自托管 Web 应用防火墙。
[](https://python.org/)
[](LICENSE)
[](https://github.com/feralbureau/zerodrop/stargazers)
[](https://github.com/feralbureau/zerodrop)
## 什么是 ZeroDrop?
**ZeroDrop** 是一个自托管的 Web 应用防火墙(WAF),它位于你的应用程序前面并实时过滤恶意流量。它使用 Caddy 的 `forward_auth` 机制拦截每个传入的请求,将其通过多层安全 pipeline 进行处理,然后决定放行还是静默丢弃。
ZeroDrop 不再需要手动配置复杂的防火墙规则,而是为你提供了一个简洁的仪表板来管理黑名单、白名单、拒绝列表、速率限制和正常运行时间监控——所有这些都由 Redis 提供支持,以实现亚毫秒级的决策速度。
## 核心功能
- **多层请求过滤**:黑名单检查、白名单旁路、蜜罐陷阱、机器人检测、SQLi/XSS 模式匹配,以及 header/query/body 检查——全部集中在单一的 pipeline 中。
- **自适应速率限制**:基于 EWMA 的限流机制,学习每个 IP 的流量模式,并具备应对突发流量的尖峰检测功能。
- **实时仪表板**:React SPA,通过 WebSocket 实时推送拦截事件和正常运行时间状态。
- **正常运行时间监控**:内置 HTTP 和 TCP 健康检查(每 30 秒一次),包含延迟历史记录和实时广播。
- **异常检测**:基于域名的每分钟请求数(RPM)跟踪与尖峰检测(滚动 5 分钟基线,3 倍阈值)。
- **动态反向代理**:自动生成并热重载 Caddy 配置——无需重启即可添加或删除受保护的域名。
- **国家与 User-Agent 拦截**:通过简单的拒绝列表管理,按 Geo-IP 国家代码或 User-Agent 字符串拒绝流量。
- **一键引导**:引导式设置流程,自动生成你的 API key,配置你的第一个域名,并应用 Caddy 配置。
## 技术栈








## 安装说明
### 前置条件
- [Docker](https://www.docker.com/get-started) 和 Docker Compose
- Git
### 环境设置
在根目录下创建一个 `.env` 文件:
```
# 提供 dashboard 的 hostname
# 如果未提供,则使用 localhost
DASHBOARD_HOST=localhost
REDIS_URL=redis://localhost:6379/0
```
### 使用 Docker 运行
```
# Clone repository
git clone https://github.com/feralbureau/zerodrop.git
cd zerodrop
# 设置你的 dashboard host
echo "DASHBOARD_HOST=localhost" > .env
# 启动所有服务
docker compose up --build
```
打开 `http://localhost` 以访问仪表板。引导流程将指导你完成初始设置。
### 本地运行(开发模式)
```
# 启动 Redis
redis-server
# 运行 API server
uvicorn app.main:app --reload
# 运行 caddy
caddy run --config caddy/Caddyfile
# 构建 dashboard
cd dashboard
npm install
npm run build
# 构建完成后,创建 srv/ 并复制由 Caddy 提供服务的 dashboard bundle
mkdir -p ../srv
cp -r dist/* ../srv/
```
仪表板服务器将可通过 `dash.localhost`(或你配置的主机)访问。
## 架构
ZeroDrop 由 Docker Compose 编排的三个容器化服务组成。Caddy 是所有流量的单一入口——它提供仪表板服务,并通过 `forward_auth` 对配置的域名强制执行 WAF 保护。
```
graph TD
Client["Client"] --> Caddy["Caddy :80/:443"]
Caddy -->|"Dashboard routes"| API["FastAPI :8000"]
Caddy -->|"forward_auth /api/check"| API
Caddy -->|"If allowed"| Origin["Protected Origin"]
API --> Redis["Redis :6379"]
API -->|"POST /load"| Caddy
```
### 请求流程
当请求到达受保护的域名时,Caddy 会先将其转发到 `/api/check`,然后再代理至源站:
```
sequenceDiagram
participant Client
participant Caddy
participant WAF as "/api/check"
participant Redis
participant Origin as "Protected Origin"
Client->>Caddy: "GET https://app.example.com/page"
Caddy->>WAF: "Forward auth (X-Real-IP, X-Original-URI)"
WAF->>Redis: "Blacklist / Allowlist / Rate checks"
alt "Allowed"
WAF-->>Caddy: "200 OK"
Caddy->>Origin: "Proxy request"
Origin-->>Client: "Response"
else "Blocked"
WAF-->>Caddy: "403 Forbidden (empty body)"
Caddy-->>Client: "Connection aborted"
end
```
### WAF Pipeline
每个请求都会按顺序在 `check_ip()` 中通过以下验证层:
1. **白名单** — 如果 IP 或 User-Agent 被列入白名单,则绕过所有检查
2. **拒绝列表** — 按 User-Agent 字符串或国家代码拦截
3. **黑名单** — 如果 IP 已被封禁则立即拒绝
4. **蜜罐** — 对敏感路径(`.env`、`/wp-admin`、`/.git` 等)实施永久封禁
5. **机器人检测** — 拦截已知的机器人 User-Agent 模式(curl、wget、scrapy 等)
6. **Header 检查** — 扫描自定义 header 中的 SQLi/XSS payload
7. **Query 检查** — 扫描 URL 参数中的恶意模式
8. **Body 检查** — 解析 JSON 或原始 body 以查找注入尝试
9. **速率限制** — 基于 EWMA 的自适应限流,具备尖峰检测功能
所有决策都会记录到 Redis stream 中,并实时广播给已连接的仪表板客户端。
## WAF 规则与开关
每个安全层都可以在仪表板中独立启用或禁用:
| 规则 | Key | 默认值 | 描述 |
|------|-----|---------|-------------|
| 白名单 | `allowlist_enabled` | 开启 | 绕过对受信任 IP/UA 的检查 |
| 蜜罐 | `honeypot_enabled` | 开启 | 对访问敏感路径的行为实施永久封禁 |
| 机器人 UA | `bot_ua_enabled` | 开启 | 拦截已知的机器人 User-Agent |
| Header 检查 | `header_inspection_enabled` | 开启 | 扫描 header 中的 SQLi/XSS |
| Query 检查 | `query_inspection_enabled` | 开启 | 扫描 URL 参数中的 payload |
| Body 检查 | `body_inspection_enabled` | 开启 | 扫描请求 body 中的注入攻击 |
| 速率限制 | `rate_limit_enabled` | 开启 | 固定窗口速率限制(60秒内 100 次请求) |
| 自适应速率限制 | `adaptive_rate_limit_enabled` | 开启 | 基于 EWMA 的动态阈值 |
| 尖峰检测 | `spike_rate_limit_enabled` | 开启 | 突发流量达到 3 倍时立即拦截 |
## API Endpoints
### REST
| Method | Endpoint | Auth | 描述 |
|--------|----------|------|-------------|
| `POST` | `/api/setup` | 无 | 初始系统设置(API key、域名、配置) |
| `GET/POST` | `/api/check` | API Key | WAF 执行 endpoint(由 Caddy 调用) |
| `GET` | `/api/key/validate` | 无 | 检查系统是否已配置 |
| `POST` | `/api/key/regenerate` | API Key | 生成新的 API key |
| `GET/PUT` | `/api/settings` | API Key | 读取/更新 WAF 设置和配置 |
| `GET/POST/DELETE` | `/api/domains` | API Key | 管理受保护的域名 |
| `GET` | `/api/logs` | API Key | 获取 WAF 事件日志 |
| `GET` | `/api/rpm` | API Key | 某个域名的 RPM 时间序列 |
| `GET` | `/api/anomalies` | API Key | 某个域名的 RPM 异常事件 |
| `GET/POST` | `/api/blacklist` | API Key | 列出/添加黑名单 IP |
| `POST` | `/api/unban` | API Key | 从黑名单中移除 IP |
| `GET/POST` | `/api/allowlist` | API Key | 列出/添加白名单条目 |
| `GET/POST` | `/api/denylist` | API Key | 列出/添加拒绝列表条目 |
| `GET/POST/DELETE` | `/api/uptime` | API Key | 管理正常运行时间监控 |
| `POST` | `/api/reset` | API Key | 清除所有数据并重新启动引导 |
### WebSocket
| Endpoint | 描述 |
|----------|-------------|
| `/api/ws/logs` | 拦截事件的实时流 |
| `/api/ws/uptime` | 实时的正常运行时间监控更新 |
| `/api/ws/ping` | 连接检查(响应 `pong`) |
## 仪表板页面
| 页面 | Path | 描述 |
|------|------|-------------|
| 仪表板 | `/` | 图表和实时安全信息流 |
| 黑名单 | `/blacklist` | 被封禁的 IP 和解封操作 |
| 白名单 | `/allowlist` | 受信任的来源和绕过规则 |
| 域名 | `/domains` | 受保护的站点和源站 |
| 设置 | `/settings` | WAF 规则和执行开关 |
## 认证
ZeroDrop 使用存储在 Redis(`waf:api_key`)中的 **API key** 进行认证。所有受保护的 endpoint 都需要通过以下方式提供 key:
- `X-API-Key` header,或
- `api_key` query 参数
WebSocket 连接也以相同方式进行身份验证。API key 在引导过程中生成,并可以随时从仪表板中重新生成。
## Redis Schema
| Key 模式 | 类型 | 用途 |
|-------------|------|---------|
| `waf:api_key` | String | 系统 API key |
| `waf:settings` | Hash | WAF 规则开关 |
| `waf:domains` | Hash | 域名 → 源站映射 |
| `profile:default` | String (JSON) | 用户昵称和头像 |
| `blacklist:{ip}` | String | 被拦截的 IP(可选 TTL) |
| `rate:{ip}` | String (counter) | 每个时间窗口的请求计数(60秒 TTL) |
| `ewma:{ip}` | String (float) | 自适应速率阈值(24小时 TTL) |
| `allow:ip`, `allow:ua` | Set | 白名单条目 |
| `deny:ua`, `deny:country` | Set | 拒绝列表条目 |
| `waf_logs` | Stream | 有序事件日志 |
| `uptime:monitors` | Set | 监控 ID |
| `uptime:monitor:{id}` | Hash | 监控配置和历史记录 |
| `rpm:count:{domain}:{minute}` | String | 原始的每分钟计数器(TTL) |
| `rpm:series:{domain}` | ZSet | RPM 序列(24小时) |
| `rpm:anomalies:{domain}` | ZSet | RPM 异常事件(24小时) |
| `rpm:first_seen:{domain}` | String | 首次记录到流量的时间戳 |
## 许可证
基于 MIT 许可证分发。查看 `LICENSE` 了解更多信息。标签:AppImage, Caddy, CISA项目, Python, WAF, Web应用防火墙, 搜索引擎查询, 无后门, 流量过滤, 自动化攻击, 请求拦截, 逆向工具, 限流