---
id: 019
title: 限流 + CAPTCHA 反爬
status: partial
labels: [security, p2]
assignee: team-lead
created_at: 2026-04-23
updated_at: 2026-04-24
---

# #019 限流 + 反爬

## 背景

当前：
- 手机号 60s 内不重发 SMS ✓
- 业务层按 user_id 限流 ✓（2026-04-24 上线）
- IP 级限流（nginx）：待做
- CAPTCHA：砍掉（见下）

风险：恶意注册刷 SMS（成本攻击）/ 爬虫扫 profile。

## 进度

### ✅ 已完成（2026-04-24，commit e9e6f54）

**业务层 rate limit（SQLite 滑动窗口，按 user_id × endpoint 计数）**

- `xiangqin.rate_limit` 模块：`check_rate_limit` / `check_group` / `prune_old`
- LIMITS：
  - `mail_send_min`: 10 / 60s
  - `mail_send_hour`: 100 / 3600s
  - `query_min`: 30 / 60s
  - `query_hour`: 500 / 3600s
- 超限：`RateLimitExceeded` → 业务层 `MailError/QueryError("rate_limited")` → HTTP 429
- SQLite 表 `rate_limit_log` + (user_id, endpoint, ts) 索引
- 21 条测试（rate_limit 单元 12 + mail 集成 3 + query 集成 2 + 已有回归）

### ❌ CAPTCHA：不做

理由：xiangqin 是 CLI-native 产品，没有 web 前端，传统 web CAPTCHA（极验 / hCaptcha / reCAPTCHA）不适配终端场景。
替代：SMS 验证码（60s 节流）+ 实名二要素核验已等效"证明真人"。
详：PRD-001 决策点，rate_limit.py 模块 docstring 也记录了。

### ⏳ 待做（优先级降为 p3）

**nginx 层 IP 限流**：业务层先上，IP 层作双保险。
- 位置：epsilon nginx conf
- 配置：`limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;`
- 触发条件：业务层限流发现有单 IP 创多账号刷 mail_send / query 时补 IP 层

## 工作量

- ✅ 业务层：0.5 人日（实际）
- ⏳ nginx IP 层：0.5 人日（未做）

## 相关

P2-2 of blueprint。
