docs(memory): 记录封禁键/取证地址分离的根因、测试与变异验证经验
This commit is contained in:
@@ -41,3 +41,45 @@
|
|||||||
两处「TTL 30 分钟」注释改成 1 小时(代码一直是 `time.Hour`)。
|
两处「TTL 30 分钟」注释改成 1 小时(代码一直是 `time.Hour`)。
|
||||||
新增 `TestShareCardCacheKeysCoverDrawnFields`——逐字段变异断言 key 必须变,
|
新增 `TestShareCardCacheKeysCoverDrawnFields`——逐字段变异断言 key 必须变,
|
||||||
去掉 Domain 立刻 FAIL。**以后改分享卡要加新字段时,先看这张测试。**
|
去掉 Domain 立刻 FAIL。**以后改分享卡要加新字段时,先看这张测试。**
|
||||||
|
|
||||||
|
## 正式环境「蜜罐封了但还能访问」排查(IPv6)
|
||||||
|
|
||||||
|
本地用 IPv6 全程复现了一遍 autoban 链路(CF-Connecting-IP 注入 + trust_proxy=true):
|
||||||
|
封禁前 200 → POST 凭据后 `IsBanned`=true → 同地址 403 → 同 /64 换地址仍 403 →
|
||||||
|
不同 /64 放行 200。**判定逻辑与中间件都正确,不是代码 bug。**
|
||||||
|
|
||||||
|
封禁键 = `shared.LimitKey(ResolveClientIP(req))`:
|
||||||
|
- IPv4 原样
|
||||||
|
- IPv6 折成 `xxxx:xxxx:xxxx:xxxx::/64`
|
||||||
|
写入(honeypot.Serve / route.NotFound)与检查(autobanMiddleware)用的是同一个函数,一致。
|
||||||
|
|
||||||
|
⇒ 「邮件说封了但能访问」只能是**键不一致**或**进程重启(封禁纯内存态)**。
|
||||||
|
三种可能:① 部署后重启过;② trust_proxy 未配 → 键是反代地址(`127.0.0.1` / `::/64`);
|
||||||
|
③ 前后请求地址族或 /64 不同(双栈、IPv6 前缀轮换、多实例)。
|
||||||
|
|
||||||
|
判定方法:`honeypot hits` / `data/honeypot-creds/creds-YYYY-MM-DD.jsonl` 里的 `ip` 字段
|
||||||
|
就是**被封的键**,与本机 `curl -6 ifconfig.co` 比对即可。
|
||||||
|
|
||||||
|
**发现的真实取证缺陷**:`db.HoneypotHit.IP` 与 creds 文件存的是折叠后的 `/64` 键,
|
||||||
|
IPv6 丢掉了精确地址(IPv4 无损);邮件里也只给键,运维会误以为「这不是我的 IP」。
|
||||||
|
建议:取证记精确 IP,封禁仍用 /64;建封与 403 命中各打一条日志。
|
||||||
|
|
||||||
|
### 据此动手改的三处(精确 IP / 封禁键分离 + 可观测性)
|
||||||
|
|
||||||
|
1. `honeypotHandler.Serve` 拆两个变量:`clientIP = ResolveClientIP`(精确,取证/邮件用)、
|
||||||
|
`banKey = LimitKey(clientIP)`(/64,封禁/采样/告警去重用)。DB 与凭据文件都写 clientIP。
|
||||||
|
2. `autoban.Options.OnBan(key, duration, reason)` 回调(新增 `ReasonProbe` / `ReasonHoneypot`),
|
||||||
|
保持 autoban 纯标准库、不再依赖 logrus。route.newBanner 注入 → 建封打 WARN
|
||||||
|
(ban_key / reason / duration / expires_at)。中间件 403 分支打 Debug。
|
||||||
|
3. 邮件同时给「来源 IP」(精确)与「封禁范围」(ban_key,仅 `ne .ip .ban_key` 时渲染);
|
||||||
|
顺手把模板里过时的「已入库」改成「写入取证文件」(上一轮凭据外置后没同步)。
|
||||||
|
|
||||||
|
副作用修掉:`honeypot stats` 的来源排行改按 `LimitKey` 合并(否则 IPv6 轮换地址会把排行碎成
|
||||||
|
几十条各 1 次)。SQL 取 `limit*4` 再合并,属近似。
|
||||||
|
|
||||||
|
测试:`TestHoneypotRecordsExactIPv6ButBansByPrefix`(精确 IP + /64 键 + store 断言)、
|
||||||
|
`TestOnBanCallback`、`TestHoneypotAlertTemplateRenders`、`TestMergeSourcesByKey`。
|
||||||
|
四处变异验证有效(改回存聚合键 / 封禁用精确地址 / 去掉 notifyBan / 不合并排行)。
|
||||||
|
|
||||||
|
**变异验证的坑**:把 `shared.LimitKey(r.IP)` 改成 `r.IP` 会因 `shared` 未使用而
|
||||||
|
**编译失败**(不是断言失败);变异要保证仍能编译(改成 `LimitKey(r.IP) + r.IP` 才测到逻辑)。
|
||||||
|
|||||||
@@ -27,3 +27,8 @@
|
|||||||
排查口诀:响应体是这句中文 → 一定是部署侧缺文件,不是代码回退。
|
排查口诀:响应体是这句中文 → 一定是部署侧缺文件,不是代码回退。
|
||||||
`getFont` 现已支持 candidates(`font_path` → `static/fonts/*` → 系统 CJK 字体)且不缓存失败,
|
`getFont` 现已支持 candidates(`font_path` → `static/fonts/*` → 系统 CJK 字体)且不缓存失败,
|
||||||
补文件后无需重启。
|
补文件后无需重启。
|
||||||
|
- ⚠️ **`GOSUMDB=off` 会让 toolchain 自动下载失败**:go.mod 要 1.27.3 而 PATH 上的 `go` 是旧版时,
|
||||||
|
会报 `golang.org/toolchain@...: verifying module: checksum database disabled by GOSUMDB=off`
|
||||||
|
(`go version` 显示的还是 shell 包装器的版本,容易误判成「版本没变」)。
|
||||||
|
解法:直接用缓存里的 toolchain 并禁用自动切换——
|
||||||
|
`PATH="$HOME/go/pkg/mod/golang.org/[email protected]/bin:$PATH" GOTOOLCHAIN=local go test ./...`
|
||||||
|
|||||||
Reference in New Issue
Block a user