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.
7.5 KiB
P11 服务端安全硬化批 — 实现计划
日期:2026-10-02 | spec:docs/specs/2026-10-02-p11-server-hardening-design.md(权威,冲突时 spec 赢)
全局约束(逐字进每个任务简报)
-
零新依赖:
crearte-server/src/go.mod与go.sum不得出现新 require;前端package.json不动。 -
Go 工具链(硬性):宿主 Go 是 1.18,不可用。所有
go build/vet/test必须在容器里跑: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会挂死。 -
禁触文件:
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/**。 -
compose 数据身份红线:不得重命名或增删任何卷(
pgdata-*、bundle-keys-*、minio-data-*、dev_node_modules、mock_node_modules)。不得改depends_on健康门控。不得移除${VAR:?…}守卫。 -
绝不
docker compose … down -v(会毁 postgres 数据、bundle keys、MinIO 对象,且 MinIO bucket 初始化须手工重做)。收尾用裸down。 -
TEST_DATABASE_URL绝不指向db-debug/pgdata-dev——db-debug与db-dev共享pgdata-dev卷,误指会清空开发数据。集成测试只用db-test(pgdata-test,127.0.0.1:5432)。 -
TDD:先写/改测试跑红,再实现跑绿;报告里贴 RED/GREEN 的命令与输出摘要。
-
每任务独立 commit,前缀
fix(security):/fix(config):/feat(observability):/chore(deploy):+ 任务号;CHANGELOG 不由任务写,控制者波次末统一补。 -
分支纪律:commit 前
git branch --show-current必须是本任务指定分支;不 merge、不 push、不碰 wrapper 仓(ROADMAP/spec/plan 记账归控制者)。crearte-server→fix/p11-server-hardeningcrearte-deploy→feat/p11-trusted-proxiescrearte→feat/p11-trusted-proxies
-
精确使用 spec 给定值:subnet 与
TRUSTED_PROXIES默认值均为172.28.0.0/24(已核实宿主172.17.0.0/16docker0、172.18.0.0/16baota_net 之外空闲);X-Real-IP用$remote_addr;Referrer-Policy用strict-origin-when-cross-origin;X-Content-Type-Options用nosniff;两个add_header都带always。 -
数量/数值必须实测核实:简报或 spec 里引用的计数(几处
location、几个add_header、几个限流器)动手前自己 grep 核准,发现不符以实测为准并在报告里披露。本仓上一波(P9-B)控制者连错两次数字(对比度 3.16 应为 2.83、「19 个 th」是行计数应为 24 元素),均由实现者纠正——这条纪律有效,继续保持。 -
验收命令(每任务收尾自跑并贴摘要):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 验收腿(控制者本人)
- 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。 - 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同值、卷名集合与改动前逐字相同。 - crearte:五腿全量不回退(vitest 626 / vue-tsc 0 / build OK / 主 e2e 80+1skip / noauth 4)——nginx 模板属部署资产,前端测试不应受影响,但必须实跑确认。
- 端到端(缺陷 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)。
- 启动日志无 D-C 告警(因为 T4 注入了
- 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;wrapperdocs/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 手动尾巴)。