# autoban 自动封禁误伤诊断报告 日期:2026-09-05 · 分析对象:`internal/security/autoban` + `internal/route/autoban.go` + `internal/shared/ip.go` ## 一、当前配置与生效机制 | 配置 | 你的值 | sample 默认 | 语义 | |---|---|---|---| | trust_proxy | true | true | 信任 CDN 权威头解析客户端 IP | | enable_auto_ban | true | true | 启用自动封禁 | | ban_threshold_sensitive | **10** | 10 | 窗口内敏感路径命中 ≥10 触发封禁 | | ban_threshold_404 | **20** | 20 | 窗口内 404 ≥20 触发封禁 | | ban_window_seconds | **10** | **60** | 统计窗口(滚动) | | ban_duration_minutes | 15 | 15 | 封禁时长 | **判定逻辑**(autoban.go Record / IsBanned): - 每个请求按「归一化客户端 IP」计数(IPv4 原样;IPv6 聚合到 /64 → `LimitKey`) - 两类事件独立计数,`敏感≥10 OR 404≥20`(10s 滚动窗口内)任一达标 → 封禁该键 15 分钟 - 已封禁键上所有后续请求直接 403 **两个计数入口**(全站仅此两处): 1. 中间件 `autoban.go:39`:请求路径命中敏感词表(`/admin`、`/.env`、`/wp-admin`、`/config`、`/db`…共 39 条前缀)→ defer 计数 2. `f.NotFound`(route.go:403):一切未匹配路由 → 404 计数后 Redirect("/") ## 二、排除项(已静态验证,非误伤来源) - ✅ **业务路由零碰撞**:全站注册路由 + 模板 77 个站内 URL 与 39 条敏感前缀**无一匹配**——正常页面打开不会误计敏感 - ✅ favicon.ico / robots.txt / sitemap / llms 均有 embed handler,不产生 404 - ✅ 404 处理器与业务性 302(语言切换/登出/投票不存在)已分离,不误计 ## 三、误伤根因(按可能性排序) ### 🔴 P0-A:客户端 IP「键折叠」→ 多用户共享同一计数键(最可能) 正常用户自己 10s 内绝不可能凑出 10 次敏感或 20 次 404(每秒 2 个 404 的强度),所以能误伤正常用户,**唯一机制是"别人的探测被记到了你的键上"**。trust_proxy=true 的解析链(ip.go ResolveClientIP): 1. 先看 `CF-Connecting-IP` / `EO-Client-IP`(权威头) 2. 都没有 → 回退 `RemoteAddr` **折叠场景**: - 若 EO 回源**未开启/未注入** `EO-Client-IP`(需在 EO 控制台确认回源透传配置),国内请求全部回退到 **EO 边缘 IP(43.174.247.x 新加坡)** → 全体大陆用户共享一个键。扫描器也走同一边缘 → 任一扫描触发 → **全国用户 403 15 分钟** - 海外 CF tunnel:cloudflared 必注 `CF-Connecting-IP`,正常不折叠;但若异常缺失则回退 `127.0.0.1` → 所有海外用户共享同一键 - sample 注释原话即为该坑:"否则解析到的将是 Cloudflare 边缘 IP,自动封禁会误伤所有访客" **自检方法**:配置 `security_alert_email`,看封禁告警里的 IP —— 若出现 43.174.247.43 / 43.174.246.43 / 127.0.0.1 这类**非用户 IP**,即实锤折叠。 ### 🔴 P0-B:运营商 CGNAT / 共享出口连坐(国内常态) 国内移动/联通/电信家宽普遍 NAT444,**成百上千真实用户共用一个公网 IPv4**。该池内任一被黑设备/扫描器探测你的站点(攻击者扫全网,你的 EO 域名是公网目标)→ 触发阈值 → 整个出口池 403 15 分钟。你本人被误伤大概率由此而来(你的出口 IP 里别人在扫站)。 ### 🟠 P1-C:IPv6 /64 聚合连坐 `LimitKey` 将 IPv6 聚合到 /64。若运营商分配粒度粗(多户共 /64)或会话前缀抖动,同段邻居的探测会连坐你。相对少见,但配置了 IPv6 解析时存在。 ### 🟠 P1-D:双 CDN 权威头互信被伪造(定向误伤) 若未按 `outputs/edgeone-cloudflare-dual-cdn-guide.md` 在两家 CDN 规则引擎删除"对方 CDN"的权威头,攻击者可伪造 `CF-Connecting-IP: <受害者IP>` 直连源站/借道 EO → 探测全部记到受害者头上 → **把任意人"定向打成 403"**。属攻击向量而非随机误伤,但同样表现为"我没干什么就 403"。 ## 四、修复建议(分级) ### P0-① 先止血(纯配置,立即可做,无需改代码) ```ini ban_window_seconds = 60 ; 10s 窗口对正常浏览太苛刻,回到默认 ban_threshold_sensitive = 30 ; 敏感命中门槛抬高(真扫描 1s 内远超此值) ban_threshold_404 = 100 ; 404 门槛抬高(正常用户+偶发爬虫不会到) security_alert_email = <你的邮箱> ; 关键:先打开告警看封禁 IP,定位是否"键折叠" ``` > 窗口越短反而越难误伤,你已比默认更保守仍误伤 → 证明误伤不是参数敏感,而是**键共享**,调参只能缓解不能根治。 ### P0-② 确认并修复 IP 解析(治本,需查服务器/控制台) 1. **源站侧**:抓一条真实请求,确认带没带 `EO-Client-IP` / `CF-Connecting-IP` 头(nginx access log 或临时 echo 头调试) - EO 域名确认开启「回源客户端 IP 透传」;无则开 2. **源站锁定**:防火墙仅放行两家 CDN 回源网段(sample 已警告;未锁定时任何人可直连伪造头) 3. 双 CDN 按指南删对端权威头 ### P1-① 代码增强(需你批准后实施) | 项 | 改动 | 效果 | |---|---|---| | 登录用户豁免 | 有有效 session 的请求不计数/不封禁 | 管理员/正常登录用户永不误伤(扫描器无 cookie) | | 封禁日志 | 封禁时 logrus 打印 ip+路径样本+UA | 事后可归因,不再"黑盒" | | UA 特征二次确认 | 敏感命中要求 UA 缺浏览器特征才加速计数 | 降低误伤 | ### P2 观察项 - 若确认 P0-A 折叠实锤:可考虑对"CDN 边缘类"键整体排除(仅当 RemoteAddr 属于 CDN 且权威头缺失时才回退 RemoteAddr——需小改 ip.go) - 监控告警邮件中的封禁频率与 IP 类型分布 ## 五、证据清单(本次分析依据) - internal/security/autoban/autoban.go:阈值判定、窗口、清理 - internal/route/autoban.go:中间件挂载、403 直接返回 - internal/route/route.go:78-84、146、403:实例化、全局挂载、404 计数 - internal/shared/ip.go:ResolveClientIP 信任链 + LimitKey /64 聚合 + 双 CDN 警告注释 - conf/app.sample.ini:默认值与设计约束说明 - 静态碰撞分析:业务路由/模板 URL × 敏感词表 = 零命中