docs: P11 server-hardening delivered (server 0.17.0 / deploy 0.7.0 / crearte 0.24.1)
ROADMAP P11 row -> 完成 with the D-A->D-A' re-pin narrative; doc index updated; CHANGELOG 0.3.4 (Done section, bilingual) recording the endpoint-verification catch: the original subnet-trust design was a rate-limit bypass under compose's docker SNAT, corrected to an empty TRUSTED_PROXIES default. Register the P11 spec + plan in the doc index.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# P11 服务端安全硬化批 — 实现计划
|
||||
|
||||
日期:2026-10-02 | spec:`docs/specs/2026-10-02-p11-server-hardening-design.md`(权威,冲突时 spec 赢)
|
||||
|
||||
## 全局约束(逐字进每个任务简报)
|
||||
|
||||
1. **零新依赖**:`crearte-server/src/go.mod` 与 `go.sum` 不得出现新 require;前端 `package.json` 不动。
|
||||
2. **Go 工具链(硬性)**:宿主 Go 是 1.18,**不可用**。所有 `go build/vet/test` 必须在容器里跑:
|
||||
|
||||
```sh
|
||||
cd <repo>/crearte-server/src && docker run --rm \
|
||||
-v "$PWD":/src -w /src \
|
||||
-v crearte_gomod:/go/pkg/mod \
|
||||
-e GOCACHE=/gocache -v crearte_gocache:/gocache \
|
||||
-e GOPROXY=https://goproxy.cn,direct -e GOSUMDB=sum.golang.google.cn \
|
||||
golang:1.24-alpine go test ./internal/api/ -run 'X' -count=1
|
||||
```
|
||||
|
||||
冷构建 1–3 分钟属正常,用 `exec` 后台 + 耐心轮询,**不要**因为没立刻出结果就重跑。`proxy.golang.org` 在本机不可达,漏掉 `GOPROXY` 会挂死。
|
||||
3. **禁触文件**:`crearte-server` 的 `internal/bundle/**`、`internal/repository/migrations/**`、`internal/storage/**`、`cmd/**`(除 spec 明列);`crearte` 的 `src/app/**`、`src/e2e/**`、`vite.config.ts`、`package.json`、各 config;`crearte-deploy` 的 `scripts/**`、`.github/**`、`backups/**`。
|
||||
4. **compose 数据身份红线**:不得重命名或增删任何卷(`pgdata-*`、`bundle-keys-*`、`minio-data-*`、`dev_node_modules`、`mock_node_modules`)。不得改 `depends_on` 健康门控。不得移除 `${VAR:?…}` 守卫。
|
||||
5. **绝不 `docker compose … down -v`**(会毁 postgres 数据、bundle keys、MinIO 对象,且 MinIO bucket 初始化须手工重做)。收尾用裸 `down`。
|
||||
6. **`TEST_DATABASE_URL` 绝不指向 `db-debug`/`pgdata-dev`**——`db-debug` 与 `db-dev` 共享 `pgdata-dev` 卷,误指会清空开发数据。集成测试只用 `db-test`(`pgdata-test`,127.0.0.1:5432)。
|
||||
7. **TDD**:先写/改测试跑红,再实现跑绿;报告里贴 RED/GREEN 的命令与输出摘要。
|
||||
8. **每任务独立 commit**,前缀 `fix(security):` / `fix(config):` / `feat(observability):` / `chore(deploy):` + 任务号;**CHANGELOG 不由任务写**,控制者波次末统一补。
|
||||
9. **分支纪律**:commit 前 `git branch --show-current` 必须是本任务指定分支;不 merge、不 push、不碰 wrapper 仓(ROADMAP/spec/plan 记账归控制者)。
|
||||
- `crearte-server` → `fix/p11-server-hardening`
|
||||
- `crearte-deploy` → `feat/p11-trusted-proxies`
|
||||
- `crearte` → `feat/p11-trusted-proxies`
|
||||
10. **精确使用 spec 给定值**:subnet 与 `TRUSTED_PROXIES` 默认值均为 `172.28.0.0/24`(已核实宿主 `172.17.0.0/16` docker0、`172.18.0.0/16` baota_net 之外空闲);`X-Real-IP` 用 `$remote_addr`;`Referrer-Policy` 用 `strict-origin-when-cross-origin`;`X-Content-Type-Options` 用 `nosniff`;两个 `add_header` 都带 `always`。
|
||||
11. **数量/数值必须实测核实**:简报或 spec 里引用的计数(几处 `location`、几个 `add_header`、几个限流器)动手前自己 grep 核准,发现不符以实测为准并在报告里披露。本仓上一波(P9-B)控制者连错两次数字(对比度 3.16 应为 2.83、「19 个 th」是行计数应为 24 元素),均由实现者纠正——这条纪律有效,继续保持。
|
||||
12. **验收命令**(每任务收尾自跑并贴摘要):server 任务 = 本包 `go test` + `go vet ./...` + `gofmt -l`(应无输出);deploy/crearte 任务见各自简报。全量腿由控制者波次末跑。
|
||||
|
||||
## 任务分解与并行度
|
||||
|
||||
文件面两两不相交才可并行。同一 Go 包内并发编辑会让兄弟任务的 `go test` 看到半成品而假红,故 **T1 与 T2 同属 `internal/api`,必须串行**。
|
||||
|
||||
| 任务 | 仓 / 包 | 改动文件 | 波次 |
|
||||
|---|---|---|---|
|
||||
| T1 限流表硬上界(缺陷 B) | server / `internal/api` | `ratelimit.go`、`ratelimit_test.go` | **1** |
|
||||
| T2 信任代理链 + 启动告警(缺陷 A、D-C) | server / `internal/api` | `router.go`、新 `clientip_test.go`、`router_test.go` | **2**(T1 后) |
|
||||
| T3 LOG 归一 + `parseTrustedProxies` 覆盖(缺陷 C) | server / `internal/config` | `config.go`、`config_test.go` | **1** |
|
||||
| T4 compose 固定 subnet + `TRUSTED_PROXIES`(D-A) | deploy | `docker-compose.yml`、`.env.example`、`README.md` | **1** |
|
||||
| T5 nginx 反代头加固(D-E) | crearte | `deploy/nginx.conf.template` | **1** |
|
||||
| T6 验收(控制者本人,不派发) | 三仓 | — | **3** |
|
||||
|
||||
**波次 1 并行**:T1 + T3 + T4 + T5(四个不同仓/包,零文件重叠)。
|
||||
**波次 2**:T2(等 T1 落地,同包串行)。
|
||||
**波次 3**:T6 控制者验收 + 终审。
|
||||
|
||||
## T6 验收腿(控制者本人)
|
||||
|
||||
1. **server**:`gofmt -l`(空)、`go vet ./...`、`go test ./... -count=1`、`go test ./... -race -count=1`、`go build ./...`;集成腿用 `db-test`(`docker compose --profile debug up -d db-test` 后 `TEST_DATABASE_URL=postgres://crearte:<pw>@127.0.0.1:5432/crearte?sslmode=disable go test ./... -count=1`),确认 skip 守卫数为 0。
|
||||
2. **deploy**:四 profile `docker compose --profile dev|prod|debug|mock config -q` 全过;`config` 输出断言 `api-prod`/`api-dev` 的 `TRUSTED_PROXIES` = `172.28.0.0/24`、`networks.default.ipam.config[0].subnet` 同值、**卷名集合与改动前逐字相同**。
|
||||
3. **crearte**:五腿全量不回退(vitest **626** / vue-tsc 0 / build OK / 主 e2e **80+1skip** / noauth **4**)——nginx 模板属部署资产,前端测试不应受影响,但必须实跑确认。
|
||||
4. **端到端(缺陷 A 的回归钉桩,最关键一腿)**:`docker compose --profile dev up -d --build` → `ps` 健康 →
|
||||
- 启动日志**无** D-C 告警(因为 T4 注入了 `TRUSTED_PROXIES`);
|
||||
- 用两个不同 `X-Forwarded-For` 各打 `/api/auth/login` 若干次,确认**各自独立计数**(改前是共享桶 → 第二个用户首次即 429;改后两个用户互不干扰);
|
||||
- 伪造抗性:客户端自带 `X-Forwarded-For: 8.8.8.8` 打一次,确认服务端日志/限流键取的是**网关追加后的真实值**而非 `8.8.8.8`;
|
||||
- `nginx -t` 校验模板渲染;确认新安全头出现在响应里(含 4xx 路径,验 `always`)。
|
||||
- 收尾 `docker compose --profile dev down`(**绝不 `-v`**)。
|
||||
5. **prod profile 冒烟**:`--profile prod up -d --build` → `/healthz` + `/metrics` → `down`。
|
||||
|
||||
## 记账(控制者,波次末)
|
||||
|
||||
- `crearte-server/docs/CHANGELOG.md` → **0.17.0**;`crearte-deploy/docs/CHANGELOG.md` → **0.7.0**;`crearte/docs/CHANGELOG.md` → **0.24.1**;wrapper `docs/CHANGELOG.md` → **0.3.4**。四仓均双语(同条目英中相邻行、条目间空行、高版本在上)。
|
||||
- 三内仓各自 `git merge --no-ff <branch>` → push → 删分支(内仓不得在 master 直接 commit)。wrapper 可 master 直提(2026-09-29 已获批)。
|
||||
- wrapper `docs/ROADMAP.md`:新增 P11 行 + 文档索引表补 spec/plan 两行(AGENTS.md 硬性要求)。
|
||||
- `memory/2026-10-02.md`:记录本波缺陷链(A 掩盖 B)、spike 方法论、以及「修一个缺陷可能让另一个从不可达变可达」这条教训。
|
||||
|
||||
## 打磨批 / 挂账(不在本批)
|
||||
|
||||
- CSP(iframe + Service Worker 加载用户作品,需独立设计批)。
|
||||
- 共享限流存储(Redis 等)——多实例化前置条件,见 spec D-G。
|
||||
- P9-B 打磨批四条(vue-router 升级复看弱断言、撤评语义进可访问名、手动关最新 toast 的播报重念、spec 口径已修)。
|
||||
- 备份恢复演练实证(`backup.sh`/`restore-drill.sh` 已交付但 prod 栈演练未跑,属 owner 手动尾巴)。
|
||||
Reference in New Issue
Block a user