fix(gateway,smtp): 修复邮件轰炸漏洞(审计 P0-1)

gateway v0.5.3 → v0.5.4:

1. gateway/src/main.cpp
   - /register/send_code 强制 CAPTCHA 校验(经 captcha:8009,Token 一次性消费,fail-closed)
   - 新增邮箱级双窗口限流(3 次/小时 + 10 次/天,CAPTCHA 通过后才计入配额)
   - 新增 _EMAIL_ADDR_RATE_HOUR / _EMAIL_ADDR_RATE_DAY 限流器实例

2. smtp/smtp_v2.py
   - 新增邮箱级长期限流兜底(EMAIL_HOURLY_LIMIT / EMAIL_DAILY_LIMIT,默认 3/10)
   - 新增全局熔断(SMTP_HOURLY_LIMIT,默认 100 封/小时,防 smtp 账号被封)
   - 预占/回滚与 60s 冷却同模式,发送失败不计入配额

3. gateway/docs/SECURITY_AUDIT_20260801.md
   - 新增带日期的安全审计报告
   - P0-1 标记为已修复 v0.5.4

4. gateway/README.md
   - 更新 /register/send_code 接口文档(CAPTCHA 必填 + 5 层防护)
   - 更新版本变更日志

防护层次:IP 限流 → CAPTCHA → 邮箱级限流(gateway)→ 60s 冷却 → 邮箱级限流(smtp)→ 全局熔断
This commit is contained in:
qing committed 2026-08-01 02:37:15 +08:00
1 parent 2774c3471f
commit 49f0698b9d
4 files changed
+424 -7

No files matched your search

+20 -5
View File
@@ -10,7 +10,8 @@ UniServe Framework 的应用层网关,C++20 实现。
- **反向代理**:携带 Token 的请求校验后转发到 `Proxy.opened` 中放开的内部服务。
- **CAPTCHA 接口**:`/captcha` 生成验证码 token + 文本(内存存储,5 分钟过期,一次性使用)。
- **邮箱验证码**:`/register/send_code` 发送 6 位验证码邮件(10 分钟有效);注册时校验,一次性消费。
- **速率限制**:登录 5 次/5 分钟、注册 3 次/10 分钟、发验证码 5 次/10 分钟,按 `X-Forwarded-For` 客户端 IP 计数(由 WAF 注入),超限一律返回 429。
- **速率限制**:登录 5 次/5 分钟、注册 3 次/10 分钟、发验证码 5 次/10 分钟(IP 级)+ 3 次/小时/10 次/天(邮箱级),按 `X-Forwarded-For` 客户端 IP 计数(由 WAF 注入),超限一律返回 429。
- **邮件轰炸防护**:`/register/send_code` 强制 CAPTCHA 校验 + 邮箱级双窗口限流(3 次/小时 + 10 次/天),smtp 层兜底同样限流 + 全局熔断(默认 100 封/小时,可配)。
- **OPTIONS 预检**:通配 `*` 返回 CORS 头,允许跨域。
## 安全特性
@@ -86,11 +87,24 @@ UniServe Framework 的应用层网关,C++20 实现。
向目标邮箱发送注册验证码(经 pymsg 调 smtp:8008 `send_email`,10 分钟有效)。
**请求体**(CAPTCHA 必填,防邮件轰炸):
```json
{ "email": "user@example.com" }
{
"email": "user@example.com",
"captcha_token": "a1b2c3d4...",
"captcha_answer": "Ab3xy"
}
```
限流 5 次/10 分钟/IP;同一邮箱 60 秒发送冷却(由 smtp 服务执行,冷却期拒绝时返回 `retry_after` 剩余秒数与提示文案,gateway 按 429 透传;已发出且在有效期内的验证码不受影响,发送失败不计入冷却)。错误码:`400`(邮箱格式错误)、`429`(IP 速率超限或同邮箱发送冷却)、`502`(smtp 服务不可用)、`500`(发送失败)。
**防护层次**:
1. IP 限流:5 次/10 分钟(`X-Forwarded-For`)
2. CAPTCHA 强制校验:经 captcha:8009 pymsg 校验,Token 一次性消费
3. 邮箱级双窗口限流:3 次/小时 + 10 次/天
4. smtp 同邮箱 60 秒发送冷却(冷却期拒绝时返回 `retry_after` 剩余秒数与提示文案,gateway 按 429 透传;已发出且在有效期内的验证码不受影响,发送失败不计入冷却)
5. smtp 邮箱级长期限流兜底 + 全局熔断(默认 100 封/小时,`SMTP_HOURLY_LIMIT` 可配)
错误码:`400`(邮箱格式错误/CAPTCHA 缺失或错误)、`429`(IP 速率超限/邮箱级限流超限/同邮箱发送冷却)、`502`(smtp 服务不可用)、`500`(发送失败)。
### `GET/POST *`(反向代理)
@@ -226,14 +240,15 @@ gateway/
## 版本
`0.5.3`(见 [src/main.cpp:30](src/main.cpp#L30))。启动时打印:
`0.5.4`(见 [src/main.cpp:31](src/main.cpp#L31))。启动时打印:
```
Gateway 0.5.3 started
Gateway 0.5.4 started
```
近期变更:
- `0.5.4`:修复邮件轰炸漏洞(审计报告 P0-1)——`/register/send_code` 强制 CAPTCHA 校验(经 captcha:8009,Token 一次性消费),新增邮箱级双窗口限流(3 次/小时 + 10 次/天);smtp 层同步增加邮箱级长期限流兜底 + 全局熔断(`SMTP_HOURLY_LIMIT` 环境变量,默认 100 封/小时)。
- `0.5.3`:配合 smtp 同邮箱 60 秒发送冷却——`/register/send_code` 在 smtp 返回 `retry_after` 时按 429 透传其提示文案(其余发送失败仍用通用 500 文案,SMTP 内部错误细节不向外暴露)。
- `0.5.2`:限流错误码统一为 429(登录原 400、注册/发码原 403,并修正 "attampts" 拼写);登录时用户不存在不再兜底 500——空结果统一走 401,并执行 dummy PBKDF2 校验拉平时序防用户名枚举;db 查询失败消息由误名的 "Login (Update Step) Failed" 改为 "Login (Query Step) Failed";pymsg 下游调用超时常量化(`DbC::DEFAULT_TIMEOUT`、`_TIMEOUT_CAPTCHA/_SMTP_VERIFY/_SMTP_SEND`)。
- `0.5.1`:登录成功后通过 db 更新 `Users.last_login`(`"$now"` 哨兵,db 日期适配层转为服务端当前 UTC 时间;更新失败经 THROW_EX_CUSTOM 抛 500,与其他步骤一致)。