母案 CM-1188 | 收尾日 2026-08-16 | 三階段落地版戰線第二棒(FR-063 編譯 ✅ → FR-064 防竄改【本案】 → FR-065 Installer) 交接軌跡見同資料夾
FR-064-LOG.md(9 棒 append-only)+FR-064-STATE.md(living 現況)。
客戶機上偵測 Nuitka 產物被竄改 → 服務立即終結+鎖定,唯一解鎖=原廠一次性 unlock token。目標「99% 不值得動手+1% 留蓄意痕跡」,B2B 法律層是真防線;離線必須成立。
build 期逐檔 SHA-256 分層 manifest(core/resources/thirdparty)
→ LC Ed25519 簽章(復用 FR-062,泛用 sign_payload/verify_payload,payload_type 判別、缺鍵視為 license 保向後相容)
→ 啟動 gate 驗章+比對 core+resources(1304 檔)→ 不符即拒啟
→ runtime 4h+jitter 抽查+業務埋點(license 匯入/SSP 匯出)
→ 偵測 tamper → 服務死透 → 雙落點(FS 標記+DB 單例表)+D9 best-effort 回報 LC
→ 重啟被 gate 攔 → 起 lockdown 殼(回 503 INTEGRITY_503001,帶 fingerprint/event_id)
→ FE interceptor 認碼 → 整站跳鎖定頁
→ 解鎖:客戶抄 fingerprint+event_id 給原廠 → LC 簽 unlock token → 放檔 restart → 核銷四關 → 解除
feature/FR-064)主要 commits97bca82e(verify_payload)、eba7f5a0/d4ef0285/607b4b3a(gate+雙落點)、b4a102b7(抽查+埋點)、build_release manifest 系列7079ae24/3f338ffc(T-6.1/6.2)、d181fdc6(D9 回報)f8133e72(核銷四關+回執回填 DB)520fc5e3(lockdown 殼)、24834d73+aeb2bd44(forensic 擴充)、e1190f86(locale C.UTF-8)、4e64ca07(殼協商改只看 Accept)2d56edb6(docker-compose,含 pki volume 補洞)、f929abe7(build_all.sh)、4c06ddc8(scripts 盤點)29fead0(CM-1240)7cc7989e(BUG-1 死透,killpg 打不到 PID 1 改依承載送訊號)、19a086af(BUG-2 指紋,掛宿主 /etc/machine-id)feature/FR-064)6ce339e(sign_payload 泛用層)、57c6566(manifest 簽章)、651db9c(unlock token 簽發:後台頁+CLI)、7c2974d(tamper 事件接收 D9)、076c06b(部署四步 SOP)feature/FR-064)de23772(鎖定頁+interceptor)、29fead0(指紋/時間預設隱藏,?details=1 才顯示)| # | 一句話 |
|---|---|
| D1 | 分層驗證:gate 全驗 core+resources、thirdparty 只由 runtime 抽查覆蓋、volume 絕不入清單 |
| D2 | 簽驗共用層:LC/BE 抽泛用 sign/verify_payload,license 向後相容(缺 payload_type 視為 license) |
| D3 | 啟動 gate 錨點=main.py validate_required_env 之後、create_app 之前,無 DB/DI 依賴 |
| D4 | /app 唯讀化:產物 root:root+進程 uid 1000+compose read_only |
| D5 | tamper 雙落點 FS+DB,任一存在即拒啟;已知限制(重建+還原可洗)明文承認 |
| D6 | unlock 離線信封:LC 簽 {machine_fingerprint, tamper_event_id, nonce, expires_at},一次性綁機 |
| D7 | 驗證邊界承認:manifest 自身不入清單、image 層驗證劃歸 FR-065 |
| D8 | 抽查 4h+jitter 0-60min,參數寫死不開放(可設定=可關閉) |
| D9 | best-effort 回報 LC(發不出不重試不阻塞),補 D5 本地可洗的洞 |
| D10 | 抽查二次確認:hash 不符立即複算,兩次皆不符才判 tamper(排除 I/O 毛刺) |
| D11 | lockdown 殼(B 方案)+forensic 證據規格+「行為人不可知」邊界明文 |
killpg(1, sig)=kill(-1, sig) POSIX 廣播特例,Linux 明文把 PID 1 排除 → master 根本沒收到訊號(非「收到卻不理」,推翻原 docstring 假設)_terminate_process 改依承載分流——gunicorn worker 指名對 master 送 SIGQUIT(有 handler,quick shutdown 不 respawn)、單 process/PID 1 直接 os._exit、bare metal 僅 pgid==pid 才 killpg(不傷 shell);master pid 由 post_fork 登記不用猜[1] Handling signal: quit → Shutting down: Master)、C-1 scheduler 路徑不同病、突變測試×3/etc/machine-id 是 0 bytes 空檔(容器不跑 systemd 永遠填不上)→ 退回 uuid.getnode()(容器 MAC,docker restart 就換)/etc/machine-id:/etc/machine-id:ro,容器指紋綁宿主機(code 不動)design.md §2 D1–D11、§4.4(D11 殼+forensic)docs/user-manual/system-integrity-lockdown-guide.md(客戶側解鎖手冊,含 ?details=1 取指紋)docs/features/.../unlock-sop.md(原廠側簽發 SOP)deployment-env.md(machine-id 掛載+read_only)CLAUDE.md(部署四步)_HOTPATH_PRIORITY_PREFIXES 全編進 binary,埋點實際只驗 binary 一檔(行為認知修正,非 bug)feature/FR-064 皆與 origin 同步docker compose -f docker/production/docker-compose.yml up -d 起正式容器(含兩 P0)