Files
tamabox/outputs/shared-egress-vote-antispam-review-2026-08-26.md
T
2026-09-08 10:10:44 +08:00

77 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 共享出口匿名投票防刷修改与测试报告
- **时间**:2026-08-26
- **目标**:解决 Cloudflare + `trust_proxy=true` 场景下,局域网用户共享公网 IP 导致同一投票只能一人提交的问题。
- **策略**:签名 `vote_fp` 负责设备级一人一票;IP 仅用于高阈值突发风控,不再承担同一投票的一票封顶。
## 修改内容
### 1. 删除匿名投票的 IP 一票封顶
`route/vote/vote.go`:
- 移除提交处理器内 `CountByIP(... 24h)` 且 `count >= 1` 即拒绝的逻辑。
- 匿名用户继续通过有效 HMAC `vote_fp` 与数据库唯一索引防止同一浏览器/设备重复投票。
- 无效或缺失 Cookie 仍会被重新签发,不会成为可信身份。
### 2. 新增投票提交专用的身份优先限流
`internal/route/ratelimit.go`:
新增 `voteSubmitRateLimitMiddleware`,投票提交同时经过两层限制:
- 登录用户:按 `user:<uid>` 独立限流,额度为常规参数的 3 倍。
- 匿名用户:按有效 `token:<vote_fp>` 独立限流。
- 所有匿名请求:同时经过 `ip:<client-ip>` 高阈值兜底限流,默认是传入基础额度的 10 倍。
- 无效/缺失 Cookie 不会获得独立 token 限流身份,只能使用 IP 兜底。
- 触发限制时返回 HTTP 429,不进入实际投票提交处理器。
`internal/route/route.go` 已将 `/vote/{token}/submit` 从普通 IP 限流切换到该专用中间件。
### 3. 校准 Cloudflare 客户端 IP 解析
`internal/shared/ip.go`:
- `TrustProxy=true` 时优先读取 Cloudflare 官方 `CF-Connecting-IP`。
- 若该头不存在或非法,再回退到 `X-Real-IP`、`X-Forwarded-For`,最后使用 `RemoteAddr`。
- `TrustProxy=false` 时仍完全忽略这些请求头,只使用 `RemoteAddr`。
- 新增 Cloudflare 头优先级和不信任代理时忽略头部的测试。
### 4. 更新设计文档
`anonymous-vote-design.md` 已同步新的防刷矩阵、token 流程和共享出口说明。
## 验证结果
通过:
```text
gofmt -d internal/route/ratelimit.go internal/route/route.go \
internal/shared/ip.go route/vote/vote.go
# 无输出
go test -count=1 ./internal/shared ./route/vote ./internal/template \
./templates ./internal/i18n ./internal/cache ./internal/security/autoban
# 全部 PASS
go vet ./route/vote ./internal/shared ./internal/template ./templates ./internal/i18n
# 无输出
```
补充测试覆盖:
- 同一共享 IP 下多个不同 token 彼此独立;
- 同一 token 仍受独立限流;
- IP 兜底允许多次正常请求,但能阻断异常突发;
- Cloudflare `CF-Connecting-IP` 优先于其他代理头;
- 未启用可信代理时伪造的代理头不会生效。
`go test ./internal/route` 当前仍无法编译完成,原因是项目既有的 `github.com/chai2010/[email protected]` 在本机缺少 CGO/WebP 编译符号,并非本次限流逻辑测试失败。
## Cloudflare 部署注意事项
1. 源站防火墙应只允许 Cloudflare 官方 IP 段访问源站端口,否则攻击者可能直接访问源站并伪造 `CF-Connecting-IP`。
2. 保持 `trust_proxy=true` 的前提是源站确实位于可信反向代理之后。
3. 重要投票建议开启 Turnstile 或要求登录;匿名签名 Cookie 只能保证设备级防重,无法阻止清 Cookie、换浏览器或自动化客户端。
4. 当前共享 IP 兜底阈值为 200 次/分钟(投票路由传入基础值 20),可根据真实并发量调整。