diff --git a/README.md b/README.md index 74b5ccc..6e8b4e0 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,15 @@ cd frontend && npm install && npm run dev 后端运行在 `http://localhost:8000`,前端在 `http://localhost:5173`。 +## 安全与限流 + +- `/api/v1/predict`: 内存滑动窗口限流(10 次/分钟/IP),多 worker 时每进程独立计数 +- 登录防爆破: 进程内内存计数,同上 +- 公网部署建议 Nginx 层限流 + `TRUST_PROXY_HEADERS=True` +- 生产环境必须配置 `ADMIN_PASSWORD` 或 `ADMIN_API_KEY`(否则管理接口 503) + +详见 [docs/06-deployment.md](docs/06-deployment.md#安全与限流)。 + ## API 概览 | 方法 | 路径 | 说明 | diff --git a/docs/06-deployment.md b/docs/06-deployment.md index 87269d8..10073cf 100644 --- a/docs/06-deployment.md +++ b/docs/06-deployment.md @@ -165,3 +165,59 @@ cat backup.sql | docker exec -i profeto-postgres psql -U football football - `/health`: 存活检查 - 日志:容器 stdout(`docker compose logs -f api`) - 评估汇总:`GET /api/v1/eval/summary`(准确率/RMSAE/校准度) + +## 安全与限流 + +### 内存限流(按进程) + +`/api/v1/predict` 与登录防爆破均使用**进程内内存**计数: + +| 机制 | 位置 | 局限 | +|------|------|------| +| `/predict` 限流 | `_RateLimiter`(内存) | 每 worker 独立计数,不共享 | +| 登录防爆破 | `_fail_times`(内存) | 同上 | + +**多 worker 部署时**(如 `uvicorn --workers 4`),每进程各自计数,实际限额为 `N × 单进程限制`。 + +### 公网部署建议 + +``` +┌─────────┐ ┌──────────┐ ┌──────────┐ +│ Client │────▶│ Nginx │────▶│ API │ +│ │ │ 限流层 │ │ 内存限流 │ +└─────────┘ └──────────┘ └──────────┘ +``` + +**推荐配置**: + +1. **Nginx 层限流**(第一道防线): + ```nginx + limit_req_zone $binary_remote_addr zone=predict:10m rate=10r/m; + location /api/v1/predict { + limit_req zone=predict burst=20 nodelay; + proxy_pass http://api:8000; + } + ``` + +2. **TRUST_PROXY_HEADERS=True** 时必须由可信反代设置 `X-Forwarded-For`: + ```nginx + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + ``` + - 若为 `False`: 仅用 `request.client.host`,忽略 `X-Forwarded-For`,防伪造 + - 若为 `True`: 解析 `X-Forwarded-For` 第一个 IP,反代后方可信 + +3. **生产环境必须配置管理鉴权**: + ```bash + APP_ENV=production + REQUIRE_ADMIN_AUTH=True + ADMIN_PASSWORD=your_secure_password + ``` + 未配置时 `/admin` 等管理接口返回 503。 + +### 参数调优 + +| 参数 | 默认 | 说明 | +|------|------|------| +| `_predict_limiter.max_requests` | 10 | 每分钟每 IP 最大请求数 | +| `_predict_limiter.window_seconds` | 60 | 滑动窗口时长 | +| `ADMIN_SESSION_TTL_HOURS` | 168 | 管理会话有效期(天) |