Guidant AI 資安檢視 · 模組報告

檔案上傳下載(jedi-file-upload)

產品裡所有附件與稽核證據檔的存取,都走這一塊。這是高風險問題最多的一塊——四道防線曾經一道都沒有,目前補了最底下那一道。

§1

這塊在產品裡做什麼

客戶在產品裡上傳的每一份東西,都經過這一塊:稽核證據、佐證文件、報告附件、系統匯出的檔案。

它平常在做什麼

  1. 使用者上傳一份檔案,系統存起來並給它一個編號
  2. 之後用那個編號下載、預覽、轉檔成 PDF、刪除
  3. 檔案本身放在雲端儲存空間,資料庫只記「誰上傳的、叫什麼名字」

為什麼這塊特別要緊

存在這裡的是稽核證據。

稽核證據如果能被別人取走、竄改或刪除,整份稽核報告的可信度就沒有了——那正是這個產品存在的理由。


§2

檢視軌跡

檢視期間:2026-09-11 ~ 2026-09-12|範圍:71 個檔案|共 3 輪

原始技術報告放在需求中心的 FR-086 站,檔名見下表最後一欄。那裡有每一輪的完整技術細節與逐條推理,供需要深究或稽核抽查時查閱。

輪次 查什麼 檔數 覆核投票 結果 原始報告檔名
B1 對外的功能入口——上傳、下載、預覽、刪除怎麼進來的 35 18 票全投完 找到 4 條(3 高 1 中)+人工另查出 1 條 scan-B1-http-boundary
B2 我們主系統這端怎麼把它接上來 10 36 票全投完 範圍內 1 條高風險+人工另查出 4 條 scan-B2-host-wiring
B1b 檔案實際存到哪裡、資料怎麼取 26 自動檢視零發現 人工找到 5 條,並直接查資料庫坐實了最後一道防線也沒有 scan-B1b-storage-backends

第三輪自動檢視「零發現」,但那一輪其實找到 5 條

這一輪是很好的例子,說明為什麼不能只看工具的結果——5 條全部是人工查出來的,包括這塊證據最扎實的那一條(統籌者與執行者各自連進開發環境,用唯讀方式查資料庫證實)。

詳見檢視方法與工具 → 為什麼不能只看 AI 的結果。

另外,開工時列的懷疑有一條被推翻了

第一輪的工作單上自己標「最重要」的那個懷疑,查證後不成立。報告裡把「是什麼擋住了它」寫清楚了——因為擋住它的如果是巧合,哪天有人整理程式碼把巧合改掉,問題就自己回來了。

這一頁還做過第二次查證:講者逐條回程式碼核對,推翻了三條

上面三輪是檢視當下的結果。這一頁定稿前,講者把每一條拿回程式碼與資料庫再對一次,結果改掉了三條:

原本寫 查證後
上傳沒有單檔大小上限 不成立——後端有 50MB 上限,而且是請求一進來就擋
連儲存空間「設定沒填就走明文」 不是沒填——七筆設定全都填了,而且全都填成不加密
借用別家帳密那條「要先做產品決策」 不是決策題——那是修另一個錯誤時留下的過渡措施,忘了拿掉

這三條的完整說明在下面各自的段落裡。把推翻的過程留在報告裡是刻意的——一份只有「找到什麼」沒有「推翻什麼」的報告,反而不可信。


§3

問題一覽

排序按風險,同風險的同一類排在一起。「出事會怎樣」那欄講的是業務影響——誰受影響、損失什麼,不是技術現象。

編號跳過 10 是刻意的:原本列了 11 條,第 10 條經查證不成立,說明在表格下方。其餘編號維持不動,方便跟先前的紀錄對照。

讀這張表之前要先知道一件事:產品還沒有出貨給任何真實客戶。

下面每一條講的「客戶會怎樣」,都是產品上線之後會發生的事,不是已經發生過的事。目前系統裡的資料全部是我們自己的測試資料。

這不會讓任何一條變得比較不嚴重——問題都是真的,只是還沒有人受害。這一輪檢視正是為了在出貨前把它們處理掉。

(一個例外:表裡凡是講「我們自己的文件網站/程式碼倉庫/測試機」的條目,與產品出不出貨無關——那些曝光是真的發生過的,已在各條裡標明。)

# 問題 風險 分類 出事會怎樣(誰受影響) 怎麼修 狀態
1 拿到檔案編號就能下載別人的檔案 🟠 高 只驗登入、不檢查歸屬 同一家公司內任何有帳號的人,都能取走別部門的稽核證據。資料庫那層補上之後,跨客戶已經擋住了,但同一客戶內跨專案、跨部門仍然拿得到 取檔之前先查出這個檔掛在哪個業務物件上,再去問那個物件的權限(第 1、2、3、7 條同一套修法) ✅ 已修(CM-2033)
2 能替任何檔案換發一張免登入的下載通行證 🟠 高 只驗登入、不檢查歸屬 通行證的機制本身是紮實的(我們自己簽、只有 120 秒、綁死一個檔案與一種用途、改內容就失效),漏掉的只有一問:換發的時候不問這個檔是不是你的。所以同公司內任何有帳號的人,拿別部門的檔案編號也換得到 換發前補上同一道歸屬檢查(與第 1、3、7 條同一套) ✅ 已修(CM-2033)
3 取檔案的那層只憑編號就交出檔案 🟠 高 只驗登入、不檢查歸屬 與第 1 條是同一件事的另一半。這一層是已經把檔案找出來、最有條件去問「這是誰的」的地方,該補檢查的就是這裡 同第 1 條,在這一層補上歸屬檢查 ✅ 已修(CM-2033)
4 上傳的網頁檔,別人點預覽時會在我們的網域裡被當成程式執行 🟠 高 外部送什麼就收什麼 受害者只要點一下預覽,攻擊者的程式就在受害者的瀏覽器裡、用受害者的身分跑起來——可以偷走他的登入狀態、冒用他的身分操作。上傳者只需要一個有效帳號 預覽端建可預覽類型清單、清單外一律當附件下載;清單內的加上瀏覽器層的隔離指令;並由伺服器自己確認檔案內容真的是那個格式。實際做法:預覽改成白名單+驗檔頭,HTML 加 CSP sandbox,不符合就強制下載 ✅ 已修(CM-2062)
5 任何登入者打一支查設定的功能,就拿到雲端儲存的帳號密碼明文 🟠 高 密碼外流 拿到那組帳密後可以完全繞過整個系統、直接連進儲存空間——之後在程式裡補再多檢查都沒用。拿到的是自己那家公司的那一組,但落地版是一客戶一套系統,那一組就是那家的全部 設定類的密碼欄位一律預設不回傳;補權限檢查;並清掉寫死在程式與腳本裡的那組帳密。五個步驟有先後順序,見下方 ✅ 已修(CM-2063)
6 存放檔案紀錄的資料表沒有做客戶隔離 🟠 高 客戶資料沒隔開 這是「四道防線都沒有」的最後一道。資料庫本身也擋不住跨客戶存取 加客戶歸屬欄位並開啟隔離 ✅ 已修(2026-09-16,2,718 筆全數補上客戶歸屬)
7 任何登入者可以永久刪除任何檔案 🟠 高 只驗登入、不檢查歸屬 別家客戶的稽核證據會被永久刪除,而且沒有救回的機制。對稽核產品來說,證據被取走還做得下去,證據被刪就做不下去了,而且不可逆 同第 1 條的歸屬檢查,但要問的是「能不能刪」而不是「能不能看」;並改成可復原的刪除 ✅ 已修(CM-2033)
8 讀不到自己的儲存設定時,系統會去借用別家客戶的帳密 🟡 中 客戶資料沒隔開 系統會繞過隔離把所有客戶的設定撈出來、取第一筆用,只留一筆警告就繼續跑。實際上借到的是最早建立的那家客戶的儲存空間——檔案會存進別人家,或去別人家找檔案 先把「撈全部取第一筆」改成「只取系統層那一列」(一行改動,風險當場消失);等錯位檔搬完再整段拿掉 ⬜ 未修
9 本機儲存刪檔時,漏清了轉檔產生的備份 🟡 中 資料清理不完整 使用者以為刪掉了,但轉出來的 PDF 還留在硬碟上——「刪了沒刪乾淨」對稽核產品是實質缺陷 補上那一步;並把兩種儲存方式的共通邏輯抽到同一處。實際做法:衍生檔清理抽成共用函式,本機儲存模式刪檔時一併清掉快取 PDF ✅ 已修(CM-2062)
12 原廠共用的檔案(例如範本),一般公司的登入帳號按刪除,硬碟上的檔案本體會先被刪掉,資料庫紀錄卻刪不掉 🟡 中 只驗登入、不檢查歸屬 刪除時是先刪檔案本體、再刪資料庫紀錄;資料庫那一步會因為不是原廠而被擋下,但檔案本體已經沒了,畫面還回「成功」。結果是原廠給所有客戶用的範本檔全部打不開,所有客戶一起受害 兩步:① 一般公司刪原廠共用檔直接拒絕;② 刪除順序改成先刪紀錄、成功才刪檔案本體 ⚠️ 部分修——第 ① 步已擋住(刪除入口補了歸屬檢查、原廠共用檔一律不准刪,1.21.0 出貨);第 ② 步刪除順序還沒改,也還沒排卡。這條是主系統掃描查出的
11 連雲端儲存時不使用加密連線 ⚪ 低 密碼外流 檔案內容與帳密在公司內部網路上以明文傳輸。目前七筆設定全部都明確填成不加密,不是漏填 出貨裝機時預設開啟加密;現有環境另外評估切換時機 🚫 裁定不修(CM-2063,決策者 2026-09-23)

原第 10 條:查證後不成立

原本寫「上傳沒有單檔大小上限、也沒有數量上限」。前半句是錯的。

實際狀況 後端有 50MB 上限,而且是請求一進來就擋,不是讓人傳完才發現
設定在哪 MAX_REQUEST_BODY_MB(設在 config/config.py,由 core/app_factory.py 套用,請求一進來就提前擋下)
前端另有一道 各個上傳元件自己也有限制,10MB~50MB 不等
最外層那道確實沒擋 前端派送程式的設定裡沒設上限,但設定檔註解明寫是刻意交給後端把關,不是疏漏

屬實的只有「數量沒有上限」這半句——但整包請求受 50MB 頂著,就算一次塞很多檔,總和一樣被擋在門外。

所以這一條從「缺陷」改判為「不成立」;「數量要不要另外訂上限」降為改善建議,不列為資安問題(訂多少是業務問題,見最後的待決策清單)。


§4

這塊最重要的一件事:四道防線

一個檔案要被不該看的人拿走,本來應該有四道關卡擋著。這塊曾經四道都沒有。

用「有人拿著一個檔案編號來要檔案」來看這四道:

第幾道 這道關卡應該問什麼 原本的狀況 現在
一、入口 你有沒有登入?這個檔案是你的嗎? 只問了前半句 ⬜ 未改
二、業務邏輯 這個編號對應的檔案,該不該給你? 完全沒問 ⬜ 未改
三、取資料 查詢時有沒有限定只能查自己的? 沒有任何範圍限制 ⬜ 未改
四、資料庫 就算前面都漏了,資料庫本身擋不擋? 表裡連「這是哪家客戶的」欄位都沒有 ✅ 已補

第四道是怎麼補上的——以及為什麼這件事值得注意

2026-09-16 那次改動,把客戶歸屬欄位加進資料表並開啟隔離,2,718 筆資料全部補上歸屬。

但那次改動不是為了修這個問題。 它是另一項功能開發順手做的——那項功能要拿這張表當暫存區,才需要加上這些欄位。

這帶出一個值得記住的現象

我們在複查時發現:這段期間補起來的都是資料庫那一層,應用程式那一層幾乎沒有動過。

「只驗登入、不檢查歸屬」那一整組問題(橫跨七個模組、十幾條)一條都沒有被碰過——而那正是我們自己標記為「最該優先處理」的那一組。

所以現在的狀態是:資料庫那道牆補上了,應用程式那道門還是開著的。 跨客戶被擋住了,但同一家客戶內跨專案、跨部門,仍然拿得到。


下面只展開需要你自己判斷、或容易被誤解的幾條。 其餘的修法明確,看上面表格的「怎麼修」那一欄就夠了——沒有展開不代表沒查,也不代表不重要。

§5

第 1、2、3、7 條:同一件事的四個出口

這四條不是四個問題,是同一個問題的四個出口:下載、換發通行證、取檔、刪除。

所以它們是一套修法,不是四套。 分開修會變成同一段判斷抄四遍,而且一定有一個出口會漏掉。

病因一句話

檔案模組不知道自己保管的檔案屬於什麼,也從來沒有去問過知道的人。

它做的事只有一行——拿編號去撈,撈到就送出。

這點很重要,因為它決定了修法方向:這不是檢查寫錯、也不是規則不夠細,是「去問一下」這個步驟從來沒有被設計進去。

先排除一個直覺但是錯的修法:用「誰上傳的」來判斷

初步的想法是「取檔案前先比對這筆資料的主人」。這個方向是錯的,因為「主人」如果指的是上傳者,會同時擋錯人、也放錯人:

會擋錯的 會放錯的
同專案的稽核員看不到證據——他不是上傳的那個人 上傳者被調離專案之後,還是看得到
上傳者離職,檔案變成沒人能開的孤兒

正確的問法不是「誰上傳的」,是「這個檔掛在哪件事情上,那件事你有份嗎」。上傳者是誰仍然要記,但那是留紀錄用的,不能當權限判準。

四個出口的差別只有一個:問的是哪一種權限

出口 要問什麼
下載、預覽(第 1 條) 這個檔掛著的那件事,你看得到嗎
換發通行證(第 2 條) 同上——通行證只是換一種拿法,門檻不該比較低
取檔那一層(第 3 條) 同上,而且這一層是最該補的地方(見下)
刪除(第 7 條) 這個檔掛著的那件事,你改得動嗎

前三個問「看得到嗎」,刪除要問「改得動嗎」。 同一個專案裡,能看證據的人通常比能刪證據的人多很多——刪除如果照抄下載的判斷,等於把刪除權放給所有看得到的人。

修法要動多少:歸屬資料一直都在,只是沒人去問

這裡要更正一個先前講錯的說法

先前說「歸屬欄位已經在表裡了,只是沒拿來用」——這句不實。檔案那張表上沒有「掛在哪個業務物件」的欄位:

欄位 實際是什麼
那個看起來像關聯的欄位(ref_id) 是「轉檔產生的 PDF 指回原始檔」的自我參照,全庫 2,821 筆裡只有 2 筆有值
上傳者欄位(owner_user_id) 96% 是空的,而且目前沒有任何規則在用它

真正的歸屬關係在下游——是那些表反過來指著檔案:

哪張表指著檔案 代表什麼檔
job_evidences.file_id 稽核證據
ssp_reference_documents.file_id 安全計畫的佐證文件
issue_upload_file_mapping.file_uid 意見單的附件

這個更正對成本判斷很重要:歸屬資料一直都在,不需要新建欄位、不需要回填舊資料——只是從來沒有人去問過它們。

修法的形狀:一個共用通道 + 一張登記表

一個很自然的顧慮是:「難道要為每一種檔案各開一支下載功能、各做一套權限檢查?」

不用。 形狀是這樣:

誰 做什麼
檔案模組 留一個空位,說「我需要一段能回答『這個人能不能拿這個檔』的程式」
各業務模組 把自己的那段回答程式登記進來
要取檔的時候 檔案模組先查出這個檔屬於哪一類,再去呼叫對應的那一段

檔案模組不懂任何業務——它只做三件事:問、等答案、照做。

各業務模組的回答程式只回答兩件事:

  1. 這個檔是不是我的(查自己那張關聯表)
  2. 如果是,這個人能不能看(用自己既有的權限規則)

第二題各業務模組本來就會算——只是從來沒有人來問過它。

那份「登記」是程式裡的一張對應表,不是資料庫的表

大約十幾列。做成資料庫的表會出問題,因為規則是活的邏輯(要查成員、看角色、算狀態),做成資料表等於用資料庫寫程式。

擴充成本:新增一種檔案用途時只加一列登記,檔案模組零改動;資料庫零改動、舊資料零回填。

有三條規則要定死,否則這套修法會有破口:

規則 為什麼
① 查不到登記的類型 → 拒絕(不是放行) 漏登記時往「看不到」倒,不是往「全都看得到」倒
② 沒有任何模組認領的檔 → 拒絕 孤兒檔不該因為沒人管就人人可取
③ 拒絕時回「找不到這個檔案」而不是「你沒有權限」 後者等於告訴對方「這個編號是有效的」,可以拿來一個一個試

這個形狀與產品既有的把關方式是一致的:「只看你是誰」的檢查掛在入口,「要先找出是什麼東西才知道該問誰」的檢查放在業務邏輯裡。檔案權限屬於後者,是目前唯一沒接上的一塊。

第 2 條的補充:通行證的機制本身是好的

產品有個功能:可以替一個檔案換發一張「通行證連結」,讓瀏覽器直接開啟檔案不用再登入一次。這個設計本身是合理的,而且做得相當紮實:

這張票 實際狀況
誰簽的 我們自己簽的,不是雲端儲存商的預簽網址
有效多久 120 秒
能開什麼 綁死一個檔案、一種用途,換不了別的
能不能偽造 有簽章,內容改一個字就失效

漏掉的只有一問:換發的時候不檢查這個檔是不是你的。 只要有帳號,拿任意檔案編號都換得到——所以它跟第 1、3、7 條是同一個病,補的是同一道檢查。

這裡刪掉了一個先前的論述:「稽核證據可以被合法帶出公司」

先前把第 2 條評得比第 1 條更嚴重,依據是「換出來的連結可以傳給公司外部的人」。

這個依據不成立。 一個人只要下載得到檔案,本來就能轉寄、存檔、拍照——任何系統都擋不住。票能不能給外人開,對「檔案會不會外流」沒有增加任何風險。 留著這句話反而給人挑毛病的把柄。

「那第 2 條要不要降級」——已裁定:不再單獨排級。

決策者 2026-09-20 裁定:第 2 條與第 1、3、7 條是同一個洞的第四個出口(都是「換發/取檔/下載/刪除時不問這個檔是不是你的」),所以不單獨討論它的等級——補上那一套歸屬檢查,四條一起消掉。風險等級一律以工單上的登記為準。

第 7 條為什麼從「中」提到與前三條同級

原本評中的依據是「這是破壞不是竊取」。這個依據對一般系統成立,對稽核產品不成立:

證據被取走 難看,但稽核還做得下去
證據被刪除 稽核做不下去了,而且不可逆——沒有救回的機制

而且查證時發現:刪除的防護比下載還薄。 下載與預覽至少接受兩條路(登入憑證或短效票),刪除只驗登入,連票那條路都沒接上,業務層也沒有任何判斷。


§6

第 4 條:上傳的網頁檔在預覽時被當成程式執行

先澄清一個常見的誤解

伺服器不會執行任何上傳上來的檔案。 整套件查證過,唯一會叫外部程式的地方是把文件轉成 PDF 的那一步,而且參數是寫死的,塞不進別的東西。

這條講的是另一件事:別人點開預覽時,攻擊者的腳本在「他的」瀏覽器裡、用「他的」身分跑起來——可以偷走他的登入狀態、冒用他的身分操作系統功能。

最有說服力的一點:同一個模組,兩個出口做法不同

出口 做法 結果
下載 一律當附件丟出去 ✅ 安全
預覽 照使用者自己填的副檔名決定格式,而且允許瀏覽器直接把它畫出來 ⚠️ 有問題

同一個模組、同一份檔案,兩條路做法不一樣。 這說明不是「不知道要做」,是預覽那一條漏掉了。

怎麼修:保留可預覽,同時關掉風險

要求是:HTML 報告要能繼續預覽。 所以不能用「乾脆全部不給預覽」這種解法。

定案的做法是三件事一起做:

做什麼 解決什麼
一 預覽端建一份可預覽的類型清單,清單外一律當附件下載 把可預覽的範圍縮到可控
二 清單內的,回應時加上瀏覽器層的隔離指令——瀏覽器會禁止這個頁面執行腳本、也不讓它碰我們網域的任何東西,排版與圖表照常看得到 就算清單內混進惡意內容也跑不起來
三 不只看副檔名,由伺服器自己確認檔案內容真的是那個格式 目前副檔名是直接拿使用者上傳的檔名,完全沒有驗證

被排除的兩個選項,以及理由:

選項 為什麼不採
轉成 PDF 再預覽 HTML 轉 PDF 常跑版、每次預覽都要等轉檔,而且只解決 HTML,不涵蓋其他格式
把上傳的檔案放到另一個網域 落地版是客戶各自裝機,多一個網域就是裝機文件上多一條——某個客戶漏做就整個失效

隔離指令之所以是首選:一行就設定完、涵蓋所有類型(包含以後才冒出來的新格式)、不需要額外建設任何東西,而且是瀏覽器本來就支援的標準做法。


§7

第 5 條:一支查詢就拿到儲存空間的帳密

這條的特別之處:它讓其他所有修補都失去意義。

拿到雲端儲存的帳號密碼之後,可以完全繞過我們的系統、直接連進儲存空間——那時候不管應用程式裡補了多少檢查,都沒有用。

三層防護同時失效:

第幾層 本來應該做什麼 實際狀況
一 用來遮蓋機密的名單,要收錄儲存設定 沒有收錄
二 要遮蓋的欄位名清單,要包含帳密欄位 沒有包含實際用的欄位名
三 查詢設定的功能要檢查權限 只檢查有沒有登入

這一條的證據等級要標清楚:是從程式碼推論成立,沒有現場實測過

開發環境還沒有設定雲端儲存,那張設定表是空的,在本機打不出症狀。這跟客戶資料隔離那一條(實際撈到筆數、任何人都能重跑)是不同等級的證據。

在稽核場合,「我們推論成立但還沒實測」是可以接受的說法;「被發現沒標」才不可接受。

影響範圍也要說清楚:那張設定表本身有做客戶隔離,所以拿到的是自己那家公司的帳密,不是全部客戶的。但落地版是一客戶一套系統,那家就是全部——對主力出貨形態沒有減輕。

修法定案:密碼類欄位預設不回傳

原則比原本的建議更強:設定類的密碼欄位一律不回傳給前端,只有程式內部要用的時候才取得真值。

做法 漏掉的時候會怎樣
原本的建議 把儲存設定補進「要遮罩」的名單 漏登記 = 密碼外洩。這次就是這樣發生的——兩份名單都漏了儲存設定
定案的做法 反過來:預設全部蓋掉,明確標記可以公開的才給 漏標記 = 頂多前端少看到一個欄位,前端會自己來反應

差別在於漏掉的時候往哪一邊倒。這個定法也順帶取消了「要不要盤查其他設定組有沒有漏登記」這個工作——預設就是蓋的,不用盤。

施工順序:五步,順序不能換

所有修法都要先確定「功能不會壞」。這一條的順序如果做錯,會把客戶的密碼洗掉。

步驟 做什麼 為什麼不能往後排
一 後端先加防護網:收到空值就保留原值、不要覆蓋 這一步必須第一個做。有了它,後面任何一步出錯都不會造成密碼被清空
二 前端改成遮蔽顯示(••••••••),不填就保持原值 跳過這步直接做第三步的話,使用者改別的欄位順手存檔,就會把密碼存成空的
三 後端改成不回傳密碼 前面兩道都到位了才動這裡
四 先查清楚有沒有背景工作在讀這組設定(匯入、排程、轉檔常常用系統身分跑),確認後再補權限檢查 不查就補,可能把它們擋掉——而且會悄悄失敗,不會有人看到錯誤
五 盤點那組帳密還寫死在哪些地方(環境變數、其他服務的設定檔、部署腳本),把它們收攏成單一來源 同一組帳密散落在很多處,日後真要換的時候必然漏掉一處,而症狀是「某個功能突然壞了」、不是明顯的錯誤訊息。趁出貨前收乾淨,成本最低

這一步不包含「換發密碼」,原因要講清楚

先前這一步寫的是「盤點完之後換發那組帳密」,前提是那組帳密已經外流。查證後這個前提不成立:

  • 這組是隨產品出給客戶的儲存空間帳密。
  • 產品從未出貨給任何真實客戶,這組帳密從頭到尾沒有離開過我們。
  • 所以沒有發生過外流,「換發」要解的那個問題並不存在。

但盤點本身仍然要做,理由換成另一個:帳密不該寫死在程式與腳本裡。這是出貨前該收乾淨的衛生問題,不是外洩應變。

要講清楚的是:這不表示第 5 條不嚴重。那個漏洞是真的——只要產品一出貨、客戶一填進自己的儲存帳密,任何有帳號的人就拿得到。差別只在於目前還沒有真實客戶受害,所以現在修的成本最低。


§8

第 8 條:讀不到自己的儲存設定時,會借到別家客戶的

這條先前寫成「要先做產品決策:客戶之間共用儲存空間是不是刻意的設計」——那個判斷是錯的。

查證結果:它不是產品決策題。它是 2026-07-29 修另一個錯誤(背景工作把檔案存錯客戶)時加上的讀取端過渡措施,當時的紀錄原話是「搬家完成前與未來零星錯位的讀取保底」。

那次已經把寫入端治本了(背景工作改成用該工作所屬的客戶去解析),這一段只是讓已經存錯位置的舊檔還讀得到。搬家從來沒做,所以它留到現在。

而且它借到的不是「系統預設」

系統層的設定確實存在(有一列是給系統用的)。但正規取系統預設的程式都會明確指定要那一列,只有這一段沒有任何條件——它是把全部撈出來、照編號排序取第一筆。

實際資料上,系統那一列的編號排在業務客戶後面,所以它永遠撈不到系統那列。實際借到的是最早建立的那家客戶的儲存空間。

現在會走到這段的三種情況

情況
① 客戶完全沒有儲存設定——目前開發環境裡有 3 個測試客戶是這樣(都是我們自己建的測試資料,不是真實客戶)
② 客戶換過儲存後端,舊檔還記著舊的型別
③ 當初那批存錯位置的舊檔

一個典型的「驗收環境打折掩蓋缺口」

開發環境的那幾筆儲存設定,位址、空間名、帳號完全相同——所以借到誰的都看不出差別,測起來一切正常。

要等客戶各自接上自己的儲存空間,這個問題才會現形。

處置定案:先一行止血,再列為待拿掉

做什麼 效果
先做 把「撈全部取第一筆」改成「只取系統層那一列」 一行改動,立刻從「借別家客戶的設定」變成「用系統預設」,風險當場消失
再做 記錄成已知的過渡措施,等錯位檔搬家完成後整段拿掉 治本

被排除的選項:先把搬家做完再拿掉這條退路——那是治本沒錯,但卡在搬家工具還沒做(工單 CM-1279),等它等不到。

另外兩件順手要做的:

補三個測試客戶的設定 開發環境有三個測試客戶完全沒有儲存設定,原因是自動複製的機制(CM-1282)只對之後新建的客戶生效,先前建的沒有回頭補。順手補一次即可
把那行警告升級 目前出事時只有一行警告混在一般日誌裡,沒有稽核事件、沒有告警。對稽核產品來說,「這個檔案到底存在誰的空間」是必須答得出來的問題

§9

第 11 條:連儲存空間時不加密

先前寫「設定沒特別填的話會走明文」——這個措辭不準確,而且差別很重要。

實際查開發環境的資料庫:七筆儲存設定全部都填了,而且全部填成不加密。

先前的寫法 實際狀況
大家忘了填(疏忽) 目前的設定就是不加密(現況)

差別在修法:不能只改預設值——現有環境都已經明確填了「不加密」,改預設對它們完全無效。

要澄清:這條與 Google Drive 無關

這條講的是我們自己裝在客戶機房的物件儲存(MinIO/SeaweedFS)那條連線。

Google Drive 走的是 Google 官方工具,底層固定加密,連「要不要加密」這個開關都沒有。目前的寫法很容易讓人誤會成 Drive 那邊也有問題。

怎麼修

出貨裝機時 預設開啟加密
現有環境 另外評估切換時機(要確認兩端都支援、切換當下會不會斷線)

§10

仍待決策的三件事

這些本頁不下結論,列出來等決策。

待決的事 目前手上的判斷依據
一 第 5 條在全案的優先順序 分析上建議排在第 1、2、3、7 條之前或同一批——理由是它修起來最便宜,而且不修的話前面那幾條的修補可以被繞過(拿到儲存帳密的人根本不走我們的門)
二 「系統共用」檔案的定義與授權規則 目前標成系統共用的那些檔在隔離規則裡是跨客戶全開的,開發環境裡有 14 筆這樣的資料(都是測試資料)。要定的是規則本身:「哪些檔案有資格標成系統共用、誰能標」——出貨前定下來,才不會讓真實客戶的檔案落進這個狀態。待決策者與 PM
三 檔案數量上限訂多少 這是業務問題——證據檔平常多大、有沒有客戶會傳影片或整包日誌。待決策者與 PM

這一輪結掉的兩件

原本列在這裡待決、2026-09-20 已裁定的兩件,記錄在此供稽核對照——不是憑空消失。

原本待決的事 裁定結果
第 2 條要不要降級 不再單獨排級。 它與第 1、3、7 條是同一個洞的第四個出口,補上同一套歸屬檢查四條一起消掉,不需要單獨討論它的等級。原本把它排在第 1 條之上的依據(「可以帶出公司」)先前已判定不成立、說明在上方
換發儲存帳密的時機 結案:不需要換發。 那是隨產品出給客戶的儲存帳密,而產品從未出貨給任何真實客戶——這組帳密從頭到尾沒有離開過我們,沒有發生過外流,「換發」要解的問題不存在。原本第五步改為「把寫死在程式與腳本裡的帳密收攏成單一來源」,說明在上方

§11

這塊的結論

一句話:這是高風險問題最多的一塊,而且它守的是稽核證據——證據能被取走、竄改或刪除,整個產品的價值就受影響。

建議:

  1. 第 1、2、3、7 條是同一件事的四個出口,一套修法涵蓋得到——下載、換發通行證、取檔、刪除。病因是「檔案模組從來沒去問過這個檔屬於什麼」,修法是「先查出它掛在哪件事上,再問那件事的權限」。歸屬資料一直都在,不需要新增欄位、不需要回填舊資料。
  2. 第 5 條建議與上面那批一起做(是否更優先待決策)——因為不修它,前面補的檢查全部可以被繞過。而且它的修法有五個步驟的先後順序,做錯會把密碼洗掉。
  3. 第 8 條不是產品決策題,是修另一個錯誤時留下的過渡措施忘了拿掉。先一行止血(改成只取系統層那一列),等檔案搬家完成再整段拿掉。

另外要提醒:第 6 條雖然標示已修,但它是別的功能開發順手做的,不是針對這個問題修的——那項功能要拿這張表當暫存區才需要加欄位。這一個月補起來的全是資料庫那一層,應用程式那一層一條都沒動過。剩下三道防線都還開著,不要因為看到「已修」就認為這塊沒事了。

最後要講清楚一件事:產品目前還沒有出貨給任何真實客戶,所以上面每一條都還沒有傷害到任何人——現在看到的檔案與設定都是我們自己的測試資料。但這不代表問題不嚴重。 每一條都是真的,產品一上線就會是真實客戶的稽核證據在承擔。這一輪檢視的目的,正是在那之前把它們處理掉——現在修,是最便宜的時候。

統計
檢視輪數 3 輪、71 個檔案
原本列出 11 條
查證後成立 10 條(1 條查證後不成立,見上方說明)
高風險 7 條
中風險 2 條
低風險 1 條
已修 1 條(資料庫層)
部分修 2 條
未修 7 條
仍待決策 3 件(見上方)
主系統掃描另查出 1 條(第 12 條,中風險,部分修)

你想知道 看哪裡
我們用什麼方法查、結果有多可信 檢視方法與工具
其他模組的檢視結果 回總報告首頁