0904
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# 共享出口匿名投票防刷修改与测试报告
|
||||
|
||||
- **时间**: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),可根据真实并发量调整。
|
||||
Reference in New Issue
Block a user