From 6fad0cbe509d4f1343a46735ffa69f588ba84988 Mon Sep 17 00:00:00 2001 From: tamakyi Date: Fri, 23 Oct 2026 15:04:14 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=AF=B4=E6=98=8E=E5=B0=81=E7=A6=81?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E7=9A=84=E5=9B=BE=E7=89=87=E4=BD=93=E4=B8=8E?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .workbuddy/memory/2026-10-23.md | 26 ++++++++++++++++++++++++++ docs/honeypot.md | 16 ++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/.workbuddy/memory/2026-10-23.md b/.workbuddy/memory/2026-10-23.md index 829baf5..0475083 100644 --- a/.workbuddy/memory/2026-10-23.md +++ b/.workbuddy/memory/2026-10-23.md @@ -153,3 +153,29 @@ Tomcat 的 skin 忘了 css(按钮白字无底色)、WP 登录页底部挂着 - 性能:RenderFamily 3.7µs→4.18µs、2→3 allocs(多的一次是 hex 编码),可接受。 四处变异验证有效(固定 token / xmlrpc 分支失效 / Pingback 相对路径 / .php 兜底失效)。 + +### 测试环境验收:XML-RPC 端点(部署 9d3f5a7 后) + +- `GET /xmlrpc.php` → **405 + text/xml**(与真实 WP 一致,XML-RPC 只接受 POST), + 用户误以为这是报错;405 的 body 是 `XML-RPC services are disabled…`。 +- `POST system.listMethods` → 200 + 方法列表 ✓。 +- `POST wp.getUsersBlogs`(伪造 `CF-Connecting-IP: 2001:db8:beef::7`)→ 凭据落文件: + `username=xruser / password=xrpass`、`fields.xmlrpc.0/1`、`xmlrpc.method`、`banned:true` ✓。 +- 紧接的下一次请求 `403 Forbidden` = 已封禁(第一次 POST 就封了该 /64),属预期。 +- 动态 token 两次不同(`d85a8c…` / `76a404…`)✓。 + +**再次出现的 `"path":" /xmlrpc.php"` 已判定为粘贴/终端产物**:`IsXMLRPCPath` 不做 trim, +若 `path` 真带前导空格根本进不了 XML-RPC 分支,而记录里有 `xmlrpc.*` 字段 ⇒ 落盘值必是 +`/xmlrpc.php`。这类"看不见的字符"结论一律靠 `od -c`,别靠终端回显。 + +### 403 响应体换成图片 + +用户给了 R2 预签名链接(`X-Amz-Expires=604800`,7 天后失效)——**不能直接热链**。 +下载后(256×256 webp,8.6 KB)用 `//go:embed` 编进二进制: +`internal/route/assets/403.webp` + `internal/route/banned.go: writeBanned()`。 +- 状态码仍是 403(语义不变),只换 body;`Content-Type: image/webp` + 显式 `Content-Length` + (8 KB 超过 Go 的 2 KB 缓冲,不设会退回 chunked)+ `no-store`;HEAD 不写 body。 +- 放在 `internal/route/assets/` 而不是 `static/`:static 会多出一个可公开访问的 URL。 +- 换图方式:覆盖同目录 403.webp → 重新编译,无配置项。 +- 体积代价:每封禁请求 8.6 KB(原 13 字节)。被封来源重试频繁时要留意带宽, + 已压到 256×256;别塞几百 KB 原图。 diff --git a/docs/honeypot.md b/docs/honeypot.md index 6bc42c1..f232726 100644 --- a/docs/honeypot.md +++ b/docs/honeypot.md @@ -110,6 +110,22 @@ honeypot_cred_dir = data/honeypot-creds 纯探测也不会被刷爆:元数据落库按「每 IP 每分钟一条」采样,凭据则是「有就存」——那才是要保的东西。 +### 被封之后会看到什么 + +状态码 `403`,body 是一张 256×256 的 webp(约 8.6 KB,画面写着 403 Forbidden),不再是那行 13 字节的明文: + +``` +$ curl -si https://你的站点/anything | head -4 +HTTP/2 403 +content-type: image/webp +content-length: 8608 +cache-control: no-store, no-cache, must-revalidate +``` + +这样做有两个目的:爆破脚本常靠读响应体里的 `403 Forbidden` 确认自己已被拦,换掉 body 让这类判断失效;人肉访问(尤其是被共享出口连累的误封)时,看到一张明确的图比白屏好判断。 + +图片用 `go:embed` 编进二进制(`internal/route/assets/403.webp`),不占任何可公开访问的 URL。想换成自己的图:覆盖同目录文件后重新编译、重启即可。注意体积——被封的来源会反复重试,8.6 KB 是刻意压过的(原图别直接塞几百 KB 的)。 + ### 封的是一把「键」,不是一个人 `autoban` 的表就是内存里的 `map[键]到期时间`,键由 `shared.LimitKey` 生成: