zlynv/drogue
GitHub: zlynv/drogue
drogue 是一个为 Python Web 框架提供生产级限流和 DDoS 防护的库,解决了传统限流方案侵入性强、缺乏 WebSocket 支持和信任区分等问题。
Stars: 1 | Forks: 0
# drogue
为 Python Web 应用提供限流和 DDoS 防护。提供简洁的 API、WebSocket 支持,并内置多层防御机制。
**[阅读文档](https://zlynv.github.io/drogue/)**
## drogue 解决什么问题?
Web 应用需要限流来防止滥用,但现有的解决方案存在以下不足:
1. **签名污染** —— 大多数限流器强制将 `request: Request` 塞进每个函数签名中,将你的业务逻辑与限流器耦合在一起。
2. **缺乏 WebSocket 防护** —— 使用 WebSocket 的实时应用没有内置的限流功能。
3. **缺乏 DDoS 检测** —— 简单的计数器可以捕捉到过度使用,但无法检测到每个客户端都保持在限制之下的分布式攻击。
4. **缺乏信任区分** —— 每个请求都经过相同的评估路径,即使是对已验证的用户也是如此。
drogue 解决了这四个问题。它通过身份(IP、用户、header)进行限流,而无需修改你的函数签名;它可以检测异常的流量模式,并为受信任的客户端提供快速通道。
## drogue 适用于谁?
- **API 开发者** —— 需要限流但不想被框架绑定
- **运行 FastAPI、Django 或 Flask 的团队** —— 希望在三种框架上使用统一的解决方案
- **面临 DDoS 或滥用的平台** —— 需要比简单请求计数更强大的防护
- **具有 WebSocket 连接的应用** —— 需要实时保护
## 工作原理
```
from fastapi import FastAPI
from drogue.adapters.fastapi import DrogueLimiter
app = FastAPI()
limiter = DrogueLimiter(app, default_limits=["100/minute"])
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():
return {"data": "value"}
```
不需要 `request: Request` 参数。限流 header 会自动注入。同样的模式也适用于 Flask 和 Django。
**请求流程:**
1. 客户端发送请求
2. drogue 提取客户端 key(IP、用户 ID 或自定义 header)
3. 根据路由匹配规则
4. 算法评估请求(令牌桶、滑动窗口或固定窗口)
5. 运行保护层(DDoS 检查、信任状态、探测器检测)
6. 返回带有限流 header 的响应
## 功能
| 类别 | 你将获得的功能 |
|----------|-------------|
| **限流** | 令牌桶、滑动窗口、固定窗口、感知成本的限流、阻塞模式、突发流量控制 |
| **身份** | 基于 IP、基于用户、基于 header、复合提取器、防伪造 X-Forwarded-For |
| **框架** | FastAPI (ASGI)、Flask (装饰器)、Django (middleware + 装饰器)、Django REST Framework (throttle) |
| **DDoS 检测** | Z-score 异常检测、流式 Sentinel 模型、探测模式检测 |
| **自动封禁** | 封禁时长倍增的渐进式封禁(5分钟至160分钟),阈值可配置 |
| **信任系统** | 状态机(未知/正常/受信任/不受信任/已封禁),已验证用户吞吐量提升 9 倍 |
| **熔断器** | Closed/Open/HalfOpen 状态,自动恢复 |
| **自适应限制** | 基于 CPU 和内存的动态调整,在系统负载下降低限制 |
| **防御随机化** | 会话级差异、蜜罐路径、防指纹追踪 |
| **CIDR 过滤** | 支持从配置或文件加载的允许/阻止列表,兼容 IPv4 和 IPv6 |
| **概率存储** | Count-Min Sketch(1M 个 key 仅需 10MB)、布隆过滤器、布谷鸟过滤器、HyperLogLog |
| **可观测性** | Prometheus 指标、OpenTelemetry 链路追踪、结构化 JSON 日志 |
| **影子模式** | 在不实际生效的情况下测试规则,上线前收集指标 |
## 性能
| 指标 | drogue | 备注 |
|--------|--------|-------|
| 令牌桶 | ~1.4us | 每次获取的中位延迟 |
| 滑动窗口 | ~1.6us | 每次获取的中位延迟 |
| 固定窗口 | ~1.1us | 每次获取的中位延迟 |
| 吞吐量 | 700K+ req/s | 单个 worker,内存存储 |
| 每个 key 的内存占用 | ~150 bytes | 进程内存储 |
*测试环境:Intel Core Ultra 5 225F,Python 3.13,asyncio 单个 worker,内存存储,10万次迭代。*
### 基准测试
运行完整的基准测试套件:
```
pip install locust pytest-benchmark
pip install -e ".[fastapi]"
# 函数级 benchmarks(无需 server)
pytest benchmarks/test_algorithm_latency.py -v --benchmark-only
pytest benchmarks/test_algorithm_throughput.py -v --benchmark-only
pytest benchmarks/test_memory.py -v --benchmark-only
# HTTP load test
python -m uvicorn benchmarks.apps.fastapi_app:app --port 8000
locust -f benchmarks/locustfile.py --headless -u 100 -r 10 --run-time 60s -H http://localhost:8000
# DDoS protection test
python -m uvicorn benchmarks.apps.ddos_app:app --port 8000
locust -f benchmarks/ddos_locustfile.py --headless -u 100 -r 10 --run-time 60s -H http://localhost:8000
```
**测试结果 (Windows, Python 3.13, MemoryStorage):**
| 测试项 | 结果 |
|------|--------|
| 函数级 ops/sec | 80-88K 次 acquire 调用/秒 |
| HTTP 吞吐量 | 2,400+ req/sec |
| DDoS 防护 | 97.8% 攻击者被封禁,p50:5ms |
## 安装
```
pip install drogue
# 使用 framework extras
pip install drogue[fastapi] # FastAPI + Starlette
pip install drogue[django] # Django
pip install drogue[flask] # Flask
pip install drogue[drf] # Django REST Framework
pip install drogue[redis] # Redis backend
pip install drogue[all] # Everything
```
## 快速入门
**FastAPI:**
```
from fastapi import FastAPI
from drogue.adapters.fastapi import DrogueLimiter
app = FastAPI()
limiter = DrogueLimiter(app, default_limits=["100/minute"])
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():
return {"data": "value"}
```
**Flask:**
```
from flask import Flask
from drogue.adapters.flask import DrogueLimiter
app = Flask(__name__)
limiter = DrogueLimiter(app, default_limits=["100/minute"])
@app.route("/api/data")
@limiter.limit("10/minute")
def get_data():
return {"data": "value"}
```
**Django:**
```
# settings.py
MIDDLEWARE = [
"drogue.adapters.django.DrogueMiddleware",
]
# views.py
from drogue.adapters.django import DrogueRateLimiter
from django.http import JsonResponse
limiter = DrogueRateLimiter()
@limiter.limit("10/minute")
def get_data(request):
return JsonResponse({"data": "value"})
```
## 从 slowapi 迁移
```
# Before(slowapi)
from slowapi import Limiter
from slowapi.util import get_remote_address
from starlette.requests import Request
limiter = Limiter(key_func=get_remote_address)
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data(request: Request):
return {"data": "value"}
# After(drogue)
from drogue.adapters.fastapi import DrogueLimiter
limiter = DrogueLimiter(app)
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():
return {"data": "value"}
```
## 已知限制
- 默认情况下,封禁状态仅存储在内存中。计划在 v0.3 版本支持 Redis 持久化。
- 信任缓存是基于单个进程的。多 worker 部署环境需要每个 worker 维护独立的信任状态。
- 对于返回字典的 Flask 视图,其限流 header 不会自动注入。
## 安全
请通过 GitHub 的私有漏洞报告功能报告安全漏洞。不要为安全漏洞开启公开的 issue。响应时间:48小时。
## 路线图
- **v0.1** —— 核心限流、DDoS 检测、支持三大框架(当前版本)
- **v0.2** —— 基于 Redis 的封禁状态、支持 Django 和 Flask 的 WebSocket
- **v0.3** —— 信任缓存跨进程同步、高级 Sentinel 功能
- **v1.0** —— 生产就绪、完整的文档站点
## 开发
```
pip install drogue[dev]
pytest
ruff check src/drogue/
```
## 许可证
MIT 许可证。详情请参阅 [LICENSE](LICENSE)。
由 [Zlynv](https://github.com/Zlynv) 创建
标签:API保护, DDoS防护, Python, WebSocket, Web中间件, 依赖分析, 搜索引擎查询, 无后门, 熔断器, 用户代理, 自定义请求头, 逆向工具, 限流