feat: harden auth and stream uploads
This commit is contained in:
13
docs/api.md
13
docs/api.md
@@ -38,7 +38,7 @@ X-API-Key: <your-api-key>
|
||||
### 2.3 匿名试用(仅网站场景)
|
||||
- 不提供 API Key;
|
||||
- 通过 Cookie 维持匿名会话(服务端签发),仅允许较小文件与较低频率。
|
||||
- 每日 10 次(以成功压缩文件数计);超出返回 `QUOTA_EXCEEDED`(HTTP `402`)。
|
||||
- 每日 10 次;进入处理即预留次数,处理失败会自动归还,不可压缩或无体积收益的有效图片仍计次。超出返回 `QUOTA_EXCEEDED`(HTTP `402`)。
|
||||
- 日界:自然日(UTC+8),次日 00:00 重置。
|
||||
- **匿名试用硬限制:Cookie + IP 双限制**(两者任一超出都拒绝),降低刷会话绕过风险。
|
||||
|
||||
@@ -59,12 +59,9 @@ Idempotency-Key: <uuid-or-random-string>
|
||||
### 3.2 限流(Rate Limit)
|
||||
超出限制返回:
|
||||
- HTTP `429`
|
||||
- 头:`Retry-After: <seconds>`
|
||||
- 错误码:`RATE_LIMITED`
|
||||
|
||||
建议头(可选):
|
||||
- `RateLimit-Limit`
|
||||
- `RateLimit-Remaining`
|
||||
- `RateLimit-Reset`
|
||||
API Key 按其 `rate_limit` 字段执行每分钟限制;登录、注册、找回密码和 Token 验证按 IP/账号执行独立限制。
|
||||
|
||||
### 3.3 配额(Quota / Billing)
|
||||
配额不足(当期额度耗尽)返回:
|
||||
@@ -496,6 +493,8 @@ Content-Type: application/json
|
||||
{ "name": "Production Server", "permissions": ["compress", "batch_compress"] }
|
||||
```
|
||||
|
||||
省略 `permissions` 时默认授予 `compress`;该权限覆盖同步压缩,并兼容批量任务、任务查询和结果下载。仅授予 `batch_compress` 时不能调用同步压缩接口。
|
||||
|
||||
响应:
|
||||
```json
|
||||
{
|
||||
@@ -721,6 +720,8 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
错误响应同时返回 `X-Request-Id`,其值与响应体 `request_id` 一致,可用于日志定位。
|
||||
|
||||
```http
|
||||
PUT /admin/storage/endpoints/{endpoint_id}
|
||||
POST /admin/storage/endpoints/{endpoint_id}/test
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
Debian 13、4 核 CPU、8GB 内存的实测起始值为 `WORKER_CONCURRENCY=2` 和 `IMAGE_PROCESSING_CONCURRENCY=2`。AVIF 是 CPU 密集型编码,不要直接把并发设置为 CPU 核数的数倍。
|
||||
|
||||
生产 Compose 默认按 8 核 16GB 主机设置可覆盖的资源上限:API 3GB、Worker 8GB、PostgreSQL 2GB、Redis 1GB;对应变量为 `API_MEMORY_LIMIT`、`WORKER_MEMORY_LIMIT`、`POSTGRES_MEMORY_LIMIT` 和 `REDIS_MEMORY_LIMIT`。Redis 的 `REDIS_MAXMEMORY` 默认 768MB,达到上限后返回写入错误而不是继续挤占宿主机内存。
|
||||
|
||||
### 首次启动
|
||||
|
||||
```bash
|
||||
|
||||
@@ -23,13 +23,15 @@
|
||||
## 2. 认证与会话
|
||||
|
||||
### 2.1 用户登录
|
||||
- 密码哈希:`argon2id`(带独立 salt,参数可配置)。
|
||||
- 登录保护:基础限速 + 失败次数冷却;可选验证码(V1+)。
|
||||
- 密码哈希:`argon2id`(独立 salt),哈希与校验在阻塞线程池执行,不占用 Tokio I/O 线程。
|
||||
- 登录保护:登录按 IP 限制为 5 分钟 30 次、按账号限制为 5 分钟 10 次;注册按 IP 限制为每小时 10 次。
|
||||
- 找回密码按 IP/邮箱双维度限速,验证和重置链接也有独立尝试上限。
|
||||
- 账号状态:`is_active=false` 直接拒绝登录与 API。
|
||||
|
||||
### 2.2 JWT 使用建议
|
||||
- 对外 API:支持 Bearer Token(适合 CLI/SDK)。
|
||||
- 网站(Vue3):优先使用 HttpOnly Cookie 承载会话(降低 XSS 泄露风险),如使用 localStorage 必须配合严格 CSP。
|
||||
- JWT 包含用户 `token_version`;修改或重置密码会递增版本,使此前签发的 JWT 立即失效。
|
||||
|
||||
---
|
||||
|
||||
@@ -48,7 +50,8 @@
|
||||
- 避免 bcrypt/argon2 用在高频 key 校验导致性能瓶颈。
|
||||
|
||||
### 3.3 权限与限制
|
||||
- 最小权限:permissions(compress/batch/read_stats/billing_read 等)。
|
||||
- API Key 请求会执行 `permissions` 校验;`compress` 权限兼容同步、批量、任务查询和结果下载。
|
||||
- 每个 API Key 使用数据库中的 `rate_limit` 执行 Redis 原子分钟限速。
|
||||
- 支持禁用/轮换;可选 IP 白名单(Business/V1+)。
|
||||
- 每次请求记录 `last_used_at/last_used_ip/user_agent`(审计)。
|
||||
|
||||
@@ -58,11 +61,13 @@
|
||||
|
||||
### 4.1 输入校验
|
||||
- 只依赖扩展名不安全:必须校验魔数/探测真实格式。
|
||||
- 单文件上传按套餐上限分片读取;批量上传边接收边落盘,不在 API 内存中累计整批文件。
|
||||
- multipart 文本字段与字段数量单独设限,文件名清除控制字符并按数据库长度安全截断。
|
||||
- 设定上限:
|
||||
- `max_file_size_mb`
|
||||
- `max_pixels`(宽×高)
|
||||
- `max_dimension`(单边)
|
||||
- 解码超时(Worker 层,避免卡死)
|
||||
- 图片处理全局并发信号量
|
||||
|
||||
### 4.2 资源隔离
|
||||
- 压缩属 CPU 密集型:放到 Worker;API 只做编排与轻量校验。
|
||||
@@ -79,7 +84,7 @@
|
||||
|
||||
- **幂等**:`Idempotency-Key` 防止重试导致重复扣费。
|
||||
- **配额硬限制**:到达当期额度返回 `QUOTA_EXCEEDED`(HTTP 402)。
|
||||
- **匿名试用**:每日 10 次(成功文件数计),采用 **Cookie + IP** 双维度 Redis 计数做硬限制。
|
||||
- **匿名试用**:每日 10 次,采用 **Cookie + IP** 双维度 Redis 原子预留;处理失败归还,已进入正常处理的不可压缩图片同样计次。
|
||||
- **异常检测**(告警即可,首期不必自动封禁):
|
||||
- 短时间内用量突增
|
||||
- 失败率异常升高(疑似 fuzzing/探测)
|
||||
@@ -114,6 +119,6 @@
|
||||
|
||||
## 8. 数据安全与保留
|
||||
|
||||
- 结果保留期:按套餐(Free 24h、Pro 7d、Business 30d 等),匿名更短。
|
||||
- 结果保留期:未登录/Free 1 天、Pro 7 天、Business 15 天,实际值由套餐的 `retention_days` 决定。
|
||||
- 支持用户主动删除任务/文件(立即删除对象存储 + DB 标记/审计)。
|
||||
- 审计日志留存与脱敏:保留必要字段(IP、UA、动作、对象 ID),避免写入明文密钥/Token。
|
||||
|
||||
Reference in New Issue
Block a user