資安檢視總報告 — 內化第四棒交接

第三棒過完 M08、M22、M09、M06,並一次結清了累積十四項的待決清單。 這份取代 _handoff-internalize-3.md(那份留著當歷史,不要再照它開場)。


§1

你的角色

陪決策者把這份資安檢視報告讀懂、想清楚、做出判斷。

他是這份報告的講者——要拿它去對客戶、對老闆、對稽核方解釋。所以他需要的不是你幫他寫完,是你講給他聽,他提問,你回答,然後把他的判斷記下來。

你是輔佐他理解的技術人員:幫他查問題、解惑、給建議。不是替他做決定的人。

工作目錄:/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be 報告原始碼在 docs/security-report/(md 是源,html 是產物)。


§2

先讀這些

  1. docs/security-report/README.md — 總報告首頁,一張表列完 23 個檢視項目
  2. docs/security-report/GUIDE-01-method-and-tools.md — 用什麼方法查、結果有多可信
  3. docs/security-report/_module-page-spec.md — 模組頁撰寫規格(了解格式即可)

§3

這份報告是什麼

PM 的要求原話:既有的技術報告「都放小弟原生產出的文件,所有過程皆需保存」,另外開一個連結放「你內化過後的版本」。

需求中心的 21 個站 這份
誰的產出 檢視工具直接吐出的技術報告 決策者消化過、認可的版本
誰負責 過程紀錄 決策者——他要能站在前面講
讀者 要查細節的工程師 客戶、老闆、稽核方

它會被當成稽核證據——所以每頁都有「檢視軌跡」段(日期、範圍、每輪票數、原始報告檔名),證明確實查過。

23 塊報告都寫好了。還沒做的是「內化」——也就是決策者的判斷。


§4

🔴 第三棒挖到的、會改變全案定位的事實

產品從未出貨給任何真實客戶

決策者 2026-09-20 告知:這一輪是出貨前的最後檢查,不是已上線系統的事後稽核。

這件事翻掉多處論述,接手後每一塊都要用它重新檢視:

作廢的論述 為什麼
「密碼可能已外流,修完要換發」 憑證從沒離開過我們
「已有 N 家客戶暴露在風險中」 那些都是開發環境測試資料
「改了會讓現有客戶掉線」 沒有客戶在跑
「要小心施工順序不能弄壞現有客戶」 多數只剩「不能弄壞打包流程」這一層

🔴 但有一類不能套用:我們自己的基礎設施(公開網站的資料庫密碼、GitLab 權杖、jedi-common/.env)與產品出不出貨無關,可能真的曾經曝光過。判準是「這東西是隨產品出給客戶的,還是我們自己在用的」。

已寫進首頁(CM-1988 做完)。後續每塊都要記得用這個前提檢視。


§5

進度

塊 狀態 決策落在
M02 檔案上傳下載 ✅ 過完 CM-1981
M01 遠端代理程式 ✅ 過完(第三棒追加兩項裁定) CM-1982
M08 防竄改 ✅ 過完 CM-1984
M22 系統設定 ✅ 過完 CM-1985
M09 系統日誌 ✅ 過完 CM-1987
M06 稽核流程 ✅ 過完(B 組經實測查證,結論與原報告不同) CM-1989
M03 弱點檢測 ⬜ 決策者指示先跳過(檢視還在跑,數字會變)
其餘 16 塊 ⬜ 下一步

目標是 23 塊全部過完,一棒接一棒做到完。


§6

🔴 M06 留下的一個教訓:首腦自己判斷錯過一次

第三棒在 M06 第 3 條上初判錯誤,被實測推翻。這件事值得下一棒記住。

經過:決策者質疑報告寫的「惡意流程圖卡死伺服器」——「我們是整份存下來、只有啟動時才算,這會造成你說的錯誤嗎?」首腦去開檔,查到主系統 _assert_all_reachable() 走訪時有 visited 集合,於是回報「報告建議的修法是在建議一個已經存在的東西,這條可能不成立」。

錯在哪:那支是存檔前的可達性檢查,不是引擎執行期走的那條路。真正會爆炸的是套件層另一組互相遞迴、沒有 visited 集合的函式。首腦看錯函式就下了結論。

派 subagent 實測後:第 3 條仍然成立(10 層閘道 2.16 秒、11 層 8.76 秒、12 層算不完),而且比報告寫的更容易觸發;反倒是第 4 條的機制描述是錯的(那支端點實測 1000 節點只要 0.027 秒)。

教訓:

  • 「我查到有防護」不等於「這條路徑有防護」——要確認查到的那支是不是使用者實際會走到的那一支,從 API 端點一路追下來。
  • 決策者的質疑方向是對的(他問的是「什麼環節會觸發」),但首腦給的答案是錯的。質疑對、答案錯,兩件事。
  • 這種「推翻報告」的判斷一定要派實測驗過再講,不要憑一次 grep 就回報。

§7

M06 的結論(已開卡 CM-1989,這裡留摘要供收尾用)

這塊最特別的發現(收尾要用):

共用套件本體 49 個檔案沒查到新問題,問題全在主系統把它接上來的那段——而那段是整個重寫的。套件原本那份有檢查,重寫的那份漏了。

14 條分四組:

  • A 組(第 1、2、5、6、9 條):只驗登入、不檢查歸屬,統一套原則二。三個要點:第 1 條拿到的清單裡有檔案編號(與 M02 是同一條鏈);第 2 條是唯一「能寫」的,留言會推播給全體成員、可冒充同事釣魚;第 6 條現在沒事是靠運氣(推進與退回都沒檢查,只是剛好被下游套件擋住)。
  • B 組(第 3、4 條):見上方教訓。修法定案五件——①記住走過哪裡(治本、零風險)②加上限(數字待定,待決 15)③那支檢查功能補權限 ④範本新增/修改要驗證 ⑤起輪次要求範本已發布。④⑤ 是報告完全沒寫的,不補的話前面的驗證都可繞過。
  • C 組(第 7 條):決策者已裁定「只能看的角色不可以完成或退回任務,只能留言」。影響面比表面大——弱點掃描模組有八支會改狀態的功能吃同一道檢查,修這條會一併解決。
  • D 組(6 條):修法明確。兩點留意——第 12、14 條是「現在無害因為沒人用」,建議直接刪掉不要留地雷;第 13 條的「部分修」是順手消失的、不是刻意修的,機制原封不動。

§8

🔴 決策者的工作偏好(前三棒踩過,務必照做)

回答要短

他明講過:「之前都太長了,雖然很詳細但很容易失焦」。先給結論再給依據、一次回答一個問題、表格優於長段落。他要的是能上台講的一句話。

不要自作主張往下跑

他會說「再來第 5 條」「回去看 M01」——照他說的走。講完一條就停,等他發問。

條數多的塊要分組講,不要逐條

第三棒在 M06(14 條)改用這招:先講這塊做什麼 → 把問題按形狀分組 → 只展開真正需要他判斷的那幾條 → 其餘列表帶過。能套既有原則的直接套,不重新討論。 決策者認可這個講法(「就這樣講」),14 條四輪對話就過完。

事實一定要回程式碼查,不要只信文件

這是最重要的一條。 前三棒在五塊裡抓到十幾條文件錯誤。

第三棒抓到的(M08/M22/M09):

報告寫的 實際
M08 第 1 條修法①「列入開機必查」 無效——換掉零件後任何簽名都會過,攻擊者可以連清單一起偽造,變成自己驗自己
M08 只有兩層檢查 有三層,漏寫了敏感操作的即時驗證(這讓第 1 條的嚴重性被低估)
M08 第 5 條「部署時只讓內部網路看得到、打不到」 這句是錯的——鎖定服務佔的就是後端對外的那個出入口,任何人都打得到
M09 第 2、4 條修法「把換行清掉」 方向錯——日誌有不可竄改的規範,應該是編碼不是刪除(決策者提出)
M22「9 個客戶的舊權限要清」 沒有 9 個客戶,產品沒出貨過(決策者提出)
M06 第 3 條修法「讓走訪時記住走過哪裡」 已經有了(決策者質疑後開檔查到)
全站的程式行號 全面失效——套件在掃描後經歷 CM-1731 版面歸位與 CM-1693 拆檔

三個查證手段,按有效性排序:

  1. 查 commit message——常常直接回答「當初為什麼這樣做」
  2. 登入實機看——188/189/190 三台
  3. 開檔看程式——不要憑報告或印象

而且前三棒自己都講錯過。 第三棒錯過三次:把「編譯了」講成「改不動」(編譯只是看不懂,檔案照樣可以整支換掉);把容器之間的設定與對外代理混為一談,誤答「鎖定服務預設不對外開」;把總表早就裁過的「測試機密碼不用換」又列成待決。講之前先查,講錯了立刻更正。

三個 repo + 實機 + 資料庫

  • 主專案:工作目錄
  • 套件:/Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/
  • 前端:/Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-fe
  • agent:/Users/chouraymond/Projects/Billows/Audit-Manager/evidence-agent
  • License Center:/Users/chouraymond/Projects/Billows/Audit-Manager/license_center(M08 用到——解鎖檔與檔案清單都是 LC 用同一把私鑰簽的)
  • 實機:ssh jedi@192.168.50.189(POC)、ssh jedi@192.168.50.190(E2E)
  • 資料庫:本機 localhost:5432 / guidant_ai_dev / .env 裡的 cmmgr,只能 SELECT

🔴 實機只能唯讀(CLAUDE.md 環境異動鐵律)。

白話

讀者是 PM 與老闆。「白話」不是把句子講得口語,是讀者完全不需要技術背景就能懂。

禁止寫「已確認安全」「沒有漏洞」「全面檢視」。

不要自己改結論

可以說「這條我覺得評太輕/太重」並說理由,但改不改由決策者決定。他的判斷會受他知道而你不知道的事影響。

第三棒有兩個實例:①M08 第 5 條我建議「LC 簽發時比對竄改回報紀錄」,決策者指出要以落地版為準、離線客戶根本送不出回報,這建議會把最需要解鎖的人擋死——當場作廢。②M22 第 1 條我建議「①要求平台管理員 + ④只給總部」疊加,決策者點出①會讓客戶完全不能自主、與落地版形態衝突——收回,單做④。


§9

派工紀律

微量查證與改稿用 subagent 即可,不必開 Notion 卡(太大才開)。

  • 一定帶 model 參數,不要繼承。機械性查證 sonnet,要組織與取捨 opus
  • prompt 第一行寫「model:X/effort:Y/理由一句」
  • 只讀不改的查證要在 prompt 裡寫死,並註明「DB 只能 SELECT、實機只能唯讀」
  • 回報只要結論,不要貼文件內容回來
  • 顯式 git add <檔名>,禁用 -am
  • commit 可自己做,push 一律等決策者明確指示。不要切 branch

🔴 subagent 的回報要自己核對過再講給決策者聽。 第一棒派去查 nginx 的那支,把「agent 那頭的 mTLS」跟「我們這頭的」當成同一道門,結論整個反了。subagent 挖到的線索有價值,但它的結論要驗。


§10

與文件首腦的分工

還有一個 session 是文件產出線的首腦,負責格式、事實驗證、build。

分界:它動格式與事實,你動內容與結論。 那 23 份 md 在內化期間以你為主。

所以你不要自己改那些 md——把要改的整理成 Notion 卡,決策者會轉給文件首腦派工。

🔴 派工卡必須交代的三件事(第三棒踩過)

  1. 施工清單列的是改動起點,不是全部——改完每一處要回頭把整頁讀一遍,把跟著矛盾的地方一起修掉。最容易留矛盾的五處:檔頭 lede、問題一覽表的「怎麼修」欄、「這塊的結論」段、統計表、跨頁引用。
  2. 自我檢查那句要寫進卡:「如果讀者只讀這一頁、從頭讀到尾,會不會讀到兩句互相打架的話?」
  3. 刪除類改動要列出 grep 關鍵詞——刪除最容易留殘句。

第三棒因為第一版卡沒寫這三件,決策者當場提醒「要記得請他內文也要調整」。


§11

已產出的卡(後面每塊照這個形狀開)

卡 內容
CM-1981 M02 檔案上傳下載
CM-1982 M01 遠端代理程式(第三棒追加 D6、D7 兩項裁定)
CM-1984 M08 防竄改
CM-1985 M22 系統設定(第四節是「產品還沒出貨」的全站影響盤點)
CM-1987 M09 系統日誌
CM-1988 全站三項裁定落地(出貨前定位/拿掉行號/M01 M02 回頭修)— 已做完
CM-1989 M06 稽核流程(第 3 條幾乎重寫、第 4 條降級)

卡的節次形狀:逐條更正(E 編號)/新發現/講者決策(D 編號)/風險等級對齊/問題分組歸類/待決清單/施工紀律/給文件首腦的施工清單。

把「事實更正」跟「講者決策」分開編號(E vs D),文件首腦一眼就知道哪些是「改錯字」、哪些是「照判斷改寫」。


§12

🔴 決策者已拍板的原則(跨模組適用,遇到同類問題直接援引)

一、密碼類欄位「預設不回傳」(標記制,不是名單制)

設定類的密碼欄位一律不回傳給前端,只有程式內部存取時取得真值。

理由:名單制漏登記=密碼外洩;標記制漏標記=頂多前端少看到一個欄位。

M22 第 3 條正是這條的活案例(兩份名單都漏掉檔案儲存那組,而寄信與員工帳號目錄已經做對了)。

二、權限檢查走「一條路由 + 登記」,不為每個情境各開路由

檔案模組留一個空位說「我需要一個能回答『這人能不能拿這個檔』的判斷函式」,各業務模組把實作登記進來。

三條要定死的規則:查不到登記的類型→拒絕;沒有模組認領的→拒絕;拒絕時回「找不到這個檔案」而不是「你沒有權限」。

「只驗登入、不檢查歸屬」那一整組都適用。M06 的 A 組五條直接套。

三、所有修法都要先判斷「功能不能壞」

講修法時要一併講:這樣改會不會壞掉、哪一步有風險、安全的施工順序。

遇到「改了會不會壞」的顧慮,先去查事實,不要停在假設。 而且現在多了一個前提:產品沒出貨,多數顧慮只剩「不能弄壞打包流程」。

四、「帶出公司」這類論述要驗證再寫

決策者推翻過「稽核證據可以被合法帶出公司」——一個人只要下載得到,本來就能轉寄、拍照,任何系統都擋不住。留著反而給人挑毛病的把柄。

後面看到類似的加重論述,先檢查它是不是「所有系統都有的事」。

五、不要相信呼叫方自報的東西,自己去查

「測試連線」入口原本收網址、照著打。決策者裁定改成收編號,後端自己去資料庫查出網址。

為什麼比「檢查」好:檢查會寫漏寫錯;不收就沒得騙。這是消除選擇,不是增加檢查。

M08 第 1 條的修法同一個家族:把零件編譯進核心層,不是「多加一道檢查」——讓「被單獨抽換」這件事物理上不可能發生。

六、🆕 落地版的設定,客戶自己要管得到(M22 第 1 條定)

產品裝在客戶機房、主機權限都在他們手上,卻要為了改密碼長度打電話給原廠,這不合理。

規則:這類「一整家客戶共用的基礎設施」設定(登入安全政策、員工帳號目錄、寄信伺服器、日誌轉送目的地),只有平台管理員與客戶組織樹最上層的管理員能改,子公司層級不能改。

問題的本質是「改的人層級不對」,不是「客戶不該能改」。

七、🆕 交出去的資料要編碼,不是刪掉(M09 第 2、4 條定)

日誌有不可竄改的規範,刪字元說不過去。換行要編碼成 \n、Excel 公式字元要標示成文字——資訊一個位元都不能少。

關鍵論述:被竄改的是現況,不是修法。 攻擊者填的是一個值,現在的系統卻讓收件方讀成兩筆紀錄——那本身就是紀錄失真。編碼是修正回忠實呈現。

一句話原則:進來的照實記,交出去的時候才負責讓它安全。


§13

🔴 浮現中的問題分組(收尾要用,每塊過完就歸類)

組 目前成員 一句話
A. 只驗登入、不檢查歸屬 M02 第 1/2/3/7 條、M06 第 1/2/5/6/9 條、報告說橫跨七個模組十幾條 最大的一組。修法=原則二
B. 鑰匙掛在牆上 M02 第 5 條、M01 第 4/5/6 條、M22 第 3 條、M16、M09 拿到憑證就繞過所有檢查
**C 的擴大版:「想到了,只做了一半」 M01 第 1/2 條與撤銷不完整、M02 第 5 條、M05 問卷、M22 第 2 條**、M06 第 1/2/9 條 不是沒想到,是做了一部分就停了。成員數可能超過 A
🆕 D. 信任鏈的起點沒人守 M08 第 1 條 驗證工具自己不在被驗證範圍內
🆕 E. 客戶層級的權限,改到全系統共用那一份 M22 第 1 條、M09 第 1 條 判準:「這個權限是客戶層級的嗎?它寫入的那份設定,全系統有幾份?」修法=原則六
🆕 F. 進來照實記,交出去沒把關 M09 第 2、4 條 與 C 組不同型:C 是「該檢查的沒檢查」,這組是「該編碼的沒編碼」。收尾看其他模組有沒有匯出/送外部系統的同型
🆕 G. 有正確版本但沒用 M06 全塊(套件 49 檔沒問題,主系統重寫的接線漏了檢查)、M08 的跨端觀察(agent 那頭做滿三層、我們這頭一層都沒有) 成因與其他組都不同——不是沒想到、也不是做一半,是東西寫對過,但被重做的時候沒跟上。M06 過完後這組已有兩個實例,建議收尾時正式立組

另一條值得收尾講的:M08 挖到「同一套憑證機制,agent 那頭做滿三層、我們這頭一層都沒有」——說明問題不是「不會做」,是兩端由不同人在不同時間做,沒有人負責檢查兩端有沒有接上。對修法可行性是正面訊息,有現成的參考實作。


§14

待決清單:舊的十四項已全部結清,M06 新增兩項

十四項的處置如下(不要再把已結的重列成待決——第三棒犯過這個錯,把總表早就裁過的「測試機密碼不用換」又列了一次):

# 待決 結果
1 M02 第 5 條優先順序 收尾一起排
2 M02 第 2 條降級 不單獨排級——與第 1/3/7 條是同一個洞的第四個出口,套原則二一起消掉
3 「系統共用」檔案規則 實作時定
4 數量上限 實作時定,給合理預設
5 換發儲存帳密時機 消掉(產品沒出貨)
6 裝機報到代碼三選一 選①:維持現狀 + 改成看得見(CM-1982 D6)
7 風險等級以哪邊為準 是文件修正不是決策
8 Zero Trust 是否生效 是查證工作,未做
9 公開網站資料庫密碼 不換(只有測試機在用,CM-1982 D7)
10 出貨流程加密碼檢查 收尾一起排
11 報告行號失效 拿掉行號只留檔名(CM-1988)
12 M08 編譯驗證誰做 併進 M08 修正工單
13 「還沒出貨」寫進首頁 要寫(CM-1988,已做完)
14 M01/M02 回頭修 要修(CM-1988,已做完)

舊清單還沒做的只有第 8 項(Zero Trust 是否已生效、涵不涵蓋文件站——影響 M01 第 5 條的狀態改寫)。那是查證不是決策,接手後可以派 subagent。

M06 新增兩項(決策者尚未定)

# 待決 需要誰
15 第 3 條的上限訂多少(分岔深度/節點總數)——要先查現有範本(含出貨預設)最複雜幾層,上限訂在那之上。報告不要自己寫死數字 講者 + PM
16 第 4 條降到哪一級——越權與無上限問題屬實,但不會癱瘓伺服器,建議由🟠高降級 講者

§15

最後的收尾(23 塊過完才做)

  • 一頁摘要(首頁最上面那段,給只看一頁的人)
  • 問題總表(141 條按嚴重度重排,現版在 docs/features/security-scan-consolidated/risk-overview.md)
  • 分析與結論(上面那七組病因,把模式講清楚)
  • 修正建議(只列優先順序,不寫日期——時程是決策者跟 PM 排的)

另有兩項業界標準補強沒做(不急):報告封面基本資料、風險評級標準說明。


§16

開場怎麼做

  1. 讀完上面三份文件(README/GUIDE-01/_module-page-spec)
  2. 用三五句話說你理解的「這份報告要解決什麼問題」
  3. 問決策者任何不清楚的
  4. 然後開始講下一塊

下一塊建議(決策者未指定,可提議讓他選):

候選 為什麼
M05 問卷 2 輪。「六個寫入入口全有檢查、八個讀取入口一個都沒有」是 C 組最乾淨的例子,講起來快
M07 證據自動分類 5 輪。風險集中在待淘汰的舊功能(填一個雲端硬碟檔案編號就能讀客戶整個硬碟)
M13 登入與權限 7 輪、查最多。13 個問題全部已修——這塊講起來是正面的,可以調節節奏

M03 弱點檢測決策者已指示先跳過(檢視還在跑,數字會變)。

不要一次講完,一塊一塊來,他要跟得上。 條數多的塊按形狀分組講,不要逐條。