---
title: 客戶資料隔離（跨模組專項）
eyebrow: Guidant AI 資安檢視 · 跨模組專項
h1: 客戶資料隔離（跨模組專項檢查）
lede: "**這不是一個模組，是橫跨所有模組的一次專項盤點**——確認「A 客戶看不到 B 客戶的東西」這件事到底有沒有真的成立。答案當時是：不成立，而且有實測數字。本頁同時記錄後續的修補進度，以及走向多家客戶共用的 SaaS 版之前還差哪一塊。"
---

::: {.callout .warn}
**先說明這一頁跟其他模組頁不一樣的地方**

其他頁講的是「某一塊功能有什麼問題」。**這一頁講的是一個橫跨整個產品的機制**——它不屬於任何一塊，而是所有塊共用的那道牆。

所以這次檢視**沒有用自動掃描工具**：答案在資料庫的實際狀態裡，不在程式碼的寫法裡，工具幫不上忙。全部由人工逐張表查證，並在開發環境實際測過。
:::

## 這件事在產品裡是什麼

Guidant AI 有兩種賣法。**落地版**是一家客戶裝一套系統在自己的機房，整座資料庫就是那家客戶的。**SaaS 版**則是多家客戶共用同一套系統，A 公司的稽核資料與 B 公司的放在同一個資料庫裡，靠一道機制隔開——**每個人查資料時，資料庫會自動幫他加上「只准看自己這家」這個條件**，不必每支程式各自記得檢查。

產品現在走的是落地版，SaaS 版有規劃、短期不上線。**但這道牆在落地版一樣要砌好**，因為同一套程式碼兩種賣法共用，而且牆本身也順帶擋住「同一家客戶內不同單位」的越界。

::: grid2
::: {.card .plain}
#### 產品說好的規則
**往下看得到，平行看不到。**

母公司看得到旗下子公司的資料；不同分支的客戶彼此完全隔開；法規框架、控制項目錄這類平台共用的東西全體可讀、只有原廠可寫。

這個規則 2026-06-29 就定案了。
:::
::: {.card .crit}
#### 為什麼這道牆特別重要
它是**最後一道防線**。

前面每一道檢查（這個人有沒有登入、有沒有權限、這筆是不是他的）**只要有一支程式漏寫，這道牆就是唯一還擋得住的東西**。

牆沒開，前面漏一次就直接外洩。
:::
:::

---

## 檢視軌跡

**檢視期間**：2026-09-11（盤點）＋ 2026-09-16、2026-09-20（兩次複查）＋ 2026-09-21（缺口清單盤點）｜**範圍**：13 張資料表 ＋ 4 個資料查詢畫面 ＋ 1 支功能入口，另加後續盤出的 102 張無牆資料表｜**共 1 輪**（人工盤點，不用自動工具）

> **原始技術報告**放在需求中心的 [FR-087 站](https://guidantai-feature-doc.jedicotech.com/FR-087-2609-tenant-isolation-audit/)，檔名見下表最後一欄。那裡有每一張表的現況、應有狀態、修法分組與「開了會不會弄壞現有功能」的逐項查證。

| 輪次 | 查什麼 | 範圍 | 覆核投票 | 結果 | 原始報告檔名 |
|---|---|---|---|---|---|
| **T1** | 每一張該隔開的資料表，牆到底有沒有開 | 13 表＋4 畫面＋1 入口 | **不適用**（人工盤點，無自動工具、無投票） | 逐項用五個固定問題查完、全部答出、歸納成七組修法；另查證兩件事、更正交接文件裡一處推測 | `scan-T1-isolation-gap-audit` |

::: {.callout .warn}
**這一輪沒有三位獨立查核投票，要講明白為什麼**

其他輪的可信度來自「三個獨立程序重查同一條、投票表決」。**這一輪沒有那道手續。**

替代的是**更硬的證據**：每一條結論都是直接問資料庫本身得到的答案（這張表的隔離開關是開是關、有幾條規則、有沒有客戶歸屬欄位），而且**用一把指向不存在客戶的鑰匙實際查過**——任何人都可以自己重跑一次驗證。

**盤點結果與來源交接文件逐項比對，13 張表與 4 個畫面一字不差**；另外更正了交接文件摘要裡寫「三個畫面」的錯誤（實際是四個）。
:::

---

## 🔴 不是理論風險，當時有實測數字

檢視當時，用一把**指向不存在客戶**的鑰匙去查——照規則應該一筆都看不到：

| 查什麼 | 應該看到 | **檢視當時實際看到** |
|---|---:|---:|
| 待辦任務列表 | 0 筆 | **39 筆** |
| 專案 | 0 筆 | **213 筆** |
| 任務執行紀錄 | 0 筆 | **11,065 筆** |
| 工作流程執行紀錄 | 0 筆 | **11,016 筆** |

（數字是 2026-09-11 檢視當時的實測結果，由統籌者在開發環境用受隔離限制的帳號重跑確認過。）

**當時客戶端還沒出事**：要真的踩到，得先有人被指派成另一家客戶的角色，而那在測試環境與展示環境當時是 0 筆。**但那個功能已經可以用了**——所以是「還沒有人踩到」，不是「踩不到」。

### 為什麼拖到那時候才發現

**這是修好一個洞之後才露出來的更大的洞。**

以前沒有人「切換客戶」過——要切換得先被指派成另一家客戶的角色，而那個功能在另一張工單修好之前根本不能用。**修好之後，才看見它後面的牆沒有砌。**

---

## 問題一覽

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

| # | 問題 | 風險 | 分類 | 出事會怎樣（誰受影響） | 怎麼修 | 狀態 |
|---|---|---|---|---|---|---|
| **1** | **13 張標有客戶歸屬的資料表，隔離沒有真正生效**（3 張規則寫好了但開關沒開、1 張規則不完整、9 張連規則都沒有） | 🟠 高 | 客戶資料沒隔開 | **一家客戶的人看得到別家客戶的專案、待辦、任務執行紀錄與稽核資料**。對一套稽核合規系統而言，這一條動搖的是產品最根本的承諾——**客戶把自己的弱點、設備清單、稽核缺失交給我們保管，前提就是別家看不到** | 分五組處理：開開關的、先補規則再開的、要補查詢規則的、要先回填資料才能開的、建議重新分類不算缺口的 | ⚠️ **大部分已修**（見下方進度） |
| **2** | **4 個資料查詢畫面整個繞過隔離機制**（使用者登入後的「我的任務」清單、判斷「這個人能做哪些操作」的權限總覽，以及兩份選單清單） | 🟠 高 | 客戶資料沒隔開 | **任何一個登入的人，打開「我的任務」頁面就會撞到**——上面那個「應該 0 筆、看到 39 筆」的待辦列表就是其中之一。**這四個畫面是用建立者的身分去查底層資料的，而建立者是系統最高權限帳號**，等於牆對它們完全不存在。稽核儀表板上的待辦數量卡片讀的也是同一個畫面 | 「我的任務」清單與權限總覽**兩支補上「用查詢者自己的身分執行」這個設定**；兩份選單清單**查遍程式找不到任何地方在用，直接移除** | ✅ **已修**（2026-09-16 複查確認；本報告撰寫時再次查證仍成立） |
| **3** | **查詢任務詳細資料的功能，收了專案編號卻從頭到尾沒用它** | 🟡 中 | 只驗登入、不檢查歸屬 | **任何登入的人在任務列表上看到一筆別人專案的任務編號，就點得開它的完整內容**。入口雖然要填專案編號，但不管填真的、全零、還是亂打一串字，**三種都查得到同一筆資料**——「這筆任務屬不屬於你說的那個專案」從來沒被檢查過 | 與檔案下載那一組（同樣的病、不同位置）合併成同一張工單處理。任務歸屬改讀輪次鏈（FR-114 CM-2113），修正未指派任務被誤擋 | ✅ **已修（CM-2039）** |
| **4** | **兩支半夜自動執行的清理程式，靠「找不到身分時給最高權限」這條規則才跑得動** | 🟡 中 | 要先做產品決策 | 這不是漏洞，是**規劃上的相依**：未來收緊那條規則的那一天，**這兩支清理程式會安靜地停止運作、而且不會報錯**，殘留資料會一直堆積卻沒人發現 | 收緊那條規則時，同時給這兩支程式一個明確的系統身分 | ✅ **已修**（2026-09-16 複查確認：兩支都改成用具名的系統身分執行，原本那段說明文字也改寫成反向警語） |
| **5** | **有一整類業務資料表連客戶歸屬欄位都沒有，牆沒有東西可以依據**——已盤清：**共 102 張沒有牆，其中 101 張連欄位都沒有** | 🟡 中 | 客戶資料沒隔開 | **落地版不受影響**——一家客戶裝一套、整座資料庫就是那家客戶的，「看到別家」這件事不成立。**但走向多家客戶共用的 SaaS 版時，合規文件那一整塊就沒有最後一道防線**：實測用一把指向不存在客戶的鑰匙去查，專案看到 **0 筆**（牆擋住了），系統安全計畫看到 **639 筆**、稽核發現看到 **525 筆** | 補上「父表看得到、子表才看得到」的跟隨規則，**不加欄位、不回填資料**。53 張要補、49 張確認不用補，真正要設計的只有 4 個接點（見下方清單） | **SaaS 版上線前必做**（清單已盤好：53 張、4 個接點；依決策者裁定排在程式面守門修完並測過一版之後） |

---

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

## 第 1 條後來怎麼了：大部分補上了

2026-09-14 一批資料庫調整把大部分缺口補起來了。**本報告撰寫時（2026-09-20）連開發環境唯讀重查**，結果如下：

| 原本的分組 | 哪些表 | 現況（唯讀實查） |
|---|---|---|
| **只需要打開開關** | 專案、客戶雲端硬碟連動設定 | ✅ 隔離已開、各 4 條規則 |
| **要先補規則再開** | 任務執行、資訊系統、矯正措施、證據分類執行紀錄、證據分類標準答案、框架解析工作、使用者角色、使用者客戶對照（8 張） | ✅ 全部已開、各 4 條規則 |
| **要補查詢規則** | 工作流程執行紀錄 | ✅ 已開、4 條規則齊 |
| **要先回填資料才能開** | 流程範本 | ✅ 已開；59 筆全部標成「平台共用」、無一筆歸屬空白 |
| **建議重新分類，不算缺口** | 日誌轉送設定 | ⚠️ 仍是關閉、0 條規則——**但這正是報告自己標「本質是平台層設定、已有權限把關，建議不當隔離缺口」的那一張** |

**而且這批新補的規則沒有踩到另一個已知的坑**：[弱點檢測那塊](M03-detection.html)查出出貨基線裡有 11 張表的隔離規則**方向寫反了**（子單位看得到母單位、母單位反而看不到子單位）。**這 13 張新補的規則逐條查過，方向全部是對的**，不會再加進那 11 條的待修清單。

**再用當時那把「指向不存在客戶」的鑰匙重測一次**（本報告撰寫時實跑）：

| 查什麼 | 檢視當時 | **現在** |
|---|---:|---:|
| 專案 | 213 筆 | **0 筆** |
| 待辦任務列表（那個繞過隔離的畫面） | 39 筆 | **0 筆** |
| 任務執行紀錄 | 11,065 筆 | **0 筆** |
| 工作流程執行紀錄 | 11,016 筆 | **0 筆** |

**這四個數字歸零，是這次專項最直接的成果。**

::: {.callout .warn}
**但「牆補好了」不等於「門也關好了」——這是整份報告反覆出現的形狀**

補牆的那批改動，**有幾筆其實是為了別的目的做的**（例如另一個功能要拿檔案表當暫存區、另一批工作在做隔離修補），跨客戶那一半順帶被擋住了，**但應用程式那一層記錄的守門缺口一行都沒動。**

具體例子：存放檔案的那張表**資料庫這道牆確實補上了**（已加客戶歸屬欄位、隔離已開、四條規則齊全，本報告撰寫時唯讀實查確認，且以受隔離的帳號查只看得到 14 筆而不是全部——這 14 筆是開發環境的測試檔案）——**但「下載檔案」「換發下載通行證」「刪除檔案」那三支功能，仍然不檢查這個檔案是不是你的。**

**意思是**：現在跨客戶擋住了，**同一家客戶內、不同專案之間仍然拿得到別人的檔案。** 這種情況必須寫成「部分修」，只寫「已修」會讓接手的人以為整條解決了。
:::

---

## 第 3 條：應用程式那一層的同型缺口，只修了一半

**已核對現況**（本報告撰寫時開檔）：

| 三支功能 | 現況 |
|---|---|
| **修改任務** | ✅ 已補上「你在這個專案裡是不是管理者」的檢查 |
| **刪除任務** | ✅ 同上 |
| **查詢任務詳細** | ❌ **一行未改**——功能入口收了專案編號，程式裡從頭到尾沒有用到它 |

而且**已經補上的那兩支也只補了一半**：它檢查的是「你在你自己填的那個專案裡是不是管理者」，**仍然沒有核對「這筆任務到底屬不屬於那個專案」**。所以拿一個自己是管理者的專案編號、配上別的專案的任務編號，檢查照樣會過。

**這是兩個不同的缺口，開工單時要分開寫。**

修法與[任務與成員管理那塊](M10-task-platform.html)的「驗了人、沒驗物」是同一種病，**併在一起做**。

---

## 第 5 條：沒有牆的那一批表已經數清楚了

### 先說結論：落地版不受影響

**落地版是一家客戶裝一套系統、整座資料庫就是那家客戶的**——裡面本來就沒有別家客戶的資料，「A 客戶看到 B 客戶」這件事在落地版根本不成立。

**這一條要等多家客戶共用同一套系統的 SaaS 版才成立**，而 SaaS 版目前有規劃、短期不上線。所以這條的狀態不寫「未修」，寫「**SaaS 版上線前必做**」——**它不是現在的洞，是產品走向 SaaS 之前的必要條件。**

### 為什麼第 1 條那批盤點會整塊漏掉

第 1 條那批只挑「**有客戶歸屬欄位**」的表來查。而合規文件那一整塊（系統安全計畫、稽核計畫、稽核結果、稽核發現、矯正措施）**本來就沒有客戶歸屬欄位**——它們是靠「屬於哪個專案」間接連到客戶的，**所以從第一步就不在清單上**。

⚠️ [合規文件那一塊](M11-oscal.html)也是**整份報告裡唯一一輪檢視都沒做過的區域**。這次盤出來的清單，就是那一塊的第一個具體待辦。

### 現在數字長這樣

| 查什麼 | 實際查到 |
|---|---:|
| 沒有牆的業務資料表 | **102 張** |
| 其中連客戶歸屬欄位都沒有的 | **101 張** |
| 用「指向不存在客戶」的鑰匙查專案 | **0 筆**（牆擋住了） |
| 同一把鑰匙查系統安全計畫 | **639 筆** |
| 同一把鑰匙查稽核發現 | **525 筆** |

### 102 張裡，要補的是 53 張

| 類別 | 張數 | 是什麼 | 要不要補 |
|---|---:|---|---|
| **A 合規文件核心** | **45** | 系統安全計畫主檔＋16 張子表（最大一張近四萬筆）、稽核計畫主檔＋6 張子表、稽核結果 3 張、稽核發現／矯正措施／改善追蹤 8 張、合規資源庫 2 張、文件共用資料 3 張、零散 5 張 | ✅ **要補** |
| **B 主專案零散** | **8** | 意見回饋 4 張（主檔有專案欄位）、任務子表 4 張（證據、留言、設備、部門）、輪次 2 張、流程控制項對照 1 張 | ✅ **要補** |
| **C 平台共用** | 12 | 法規框架、目錄、控制項與段落（五萬多筆）、弱點檢測工具與規則、能力點、選單 | ❌ 不用——**全體客戶本來就該讀得到，只有原廠能寫** |
| **D 系統層** | 15 ＋ 日誌分區 14 | 登入紀錄、登入憑證、密碼變更、版本紀錄、防竄改事件 | ❌ 不用——**這些資料沒有客戶主人** |

（公告與部門的對照表已另外裁定「靠主表擋」，不列在內。）

### 修法只有一種形狀，不是 53 套設計

**53 張全部走同一種規則**：「**父表看得到，子表才看得到**」——第 1 條那批就已經有幾張是這樣補的。**不加欄位、不回填資料**，子表一層一層跟著主檔走。

**真正要設計的只有 4 個接點**：

| 接點 | 怎麼連到客戶 |
|---|---|
| 系統安全計畫 | 靠一張對照表連到專案（**那張對照表已經有牆**） |
| 稽核計畫 | 靠另一張對照表連到專案（**已經有牆**） |
| 意見回饋 | 主檔本身就有專案欄位 |
| 🔴 **合規資源庫** | **目前沒有任何連到客戶或專案的欄位，要先決定主人是誰**。另有一張同名的資源庫表既有客戶欄位也有牆，**兩張怎麼對應要先查清楚**。**這是 4 個接點裡唯一要動腦的** |

**工作量**：一支資料庫調整、一到兩天，**外加驗證「開了牆會不會把正在用的資料藏起來」**。這個驗證不能省——第 1 條修補時就踩過，流程範本那 59 筆得先回填歸屬才能開牆。

### 業界怎麼做（放在這裡給讀者對照）

多家客戶共用的系統，隔離不外乎三種做法：

| 做法 | 說明 | 我們的位置 |
|---|---|---|
| **一家客戶一套資料庫** | 隔離最徹底，但維運成本高 | **落地版就是這種** |
| **共用資料庫、每張表帶客戶欄位、由資料庫自動加條件** | 主流的 SaaS 做法 | **產品現在走這條，但只做了外圍** |
| **只在程式裡每支查詢自己擋** | 最不安全——漏一支就破 | **這輪查出的「只驗登入、不檢查歸屬」全是這種** |

**子表沒有客戶欄位時，標準做法有兩種**：子表也加一個欄位、從父表複製；或規則直接寫「**父表看得到才看得到**」。**產品選的是後者**，與第 1 條的修補方式一致。

::: {.callout .decided}
**決策者裁定：風險維持中，順序排在程式面之後**

**為什麼不提高風險等級**：落地版一家客戶裝一套，這條不成立；只有 SaaS 版需要，而 SaaS 版短期不上線。

**順序定成三步，不可對調**：

1. **先修程式面的守門缺口**——那是現在就有、落地版也會中的。
2. **測試一版**。
3. **再開這道牆**。

**理由**：程式面先修、跑過一版之後，資料歸屬會被整理乾淨，到時候開牆踩到「**在用的資料被藏起來**」的坑會少很多。

**歸屬**：併進合規文件那一塊處理。**總報告收尾的修正建議要把它列成明確的第二階段**，排在程式面修正與測試之後——**不要讓「晚一點」變成忘記。**
:::

---

## 這塊的結論

::: {.callout .warn}
**一句話**：這次專項最大的價值不是找到一個洞，是**把「資料庫這道牆現在到底是什麼狀態」從猜測變成一張可以逐項驗證的清單**——而且當場用一個任何人都能重跑的測試證明它沒生效。後續大部分已經補上，實測數字從 39／213／11,065／11,016 全部歸零。

**這次專項也留下兩件事，必須一起看**：

**一、牆補好了，門還開著。** 應用程式那一層「這筆資料是不是你的」的檢查，是整份報告裡**最大的一組未修項目**，一條都沒被碰過。牆擋的是「別家客戶」，門擋的是「同一家客戶裡不該看的人」——**兩者不能互相取代。這是現在就存在、落地版也會中的問題。**

**二、走向 SaaS 版之前還差一塊，而且已經數清楚了。** 沒有牆的業務資料表共 102 張，其中**要補的是核心合規文件 45 張＋零散 8 張，合計 53 張**，修法只有「父表看得到、子表才看得到」一種形狀，真正要設計的只有 4 個接點、一到兩天的工作量。**落地版不受這一塊影響**——一家客戶裝一套，整座資料庫就是那家客戶的。

**建議照這個順序做**：

1. **先修應用程式那一層的守門缺口**——與其他模組的同型問題併成同一批處理，這是現在就有的風險。
2. **測試一版**，讓資料歸屬在這個過程裡被整理乾淨。
3. **再把那 53 張的牆開起來**，併進合規文件那一塊，作為 SaaS 版上線前的必要條件。
:::

| 統計 | |
|---|---|
| 檢視輪數 | 1 輪（人工盤點）＋ 2 次複查 ＋ 1 次缺口清單盤點 |
| 盤點範圍 | 13 張資料表 ＋ 4 個資料查詢畫面 ＋ 1 支功能入口，另加 102 張無牆資料表 |
| 歸納出的修法分組 | 7 組 |
| 最嚴重 | 0 條 |
| 高風險 | 2 條（1 條大部分已修、1 條已修） |
| 已修 | 2 條（第 2、4 條） |
| 部分修 | 2 條（第 1、3 條） |
| 列為 SaaS 版上線前必做 | 1 條（第 5 條，落地版不成立；待補清單 53 張、4 個接點已盤好） |
| 未修 | 0 條（五條全部有著落：兩條已修、兩條部分修、一條排入 SaaS 版上線前）|
| 已開工單 | 0 張（決策者裁定先登記、修正工單另批統一開） |

---

| 你想知道 | 看哪裡 |
|---|---|
| 我們用什麼方法查、結果有多可信 | [檢視方法與工具](GUIDE-01-method-and-tools.html) |
| 其他模組的檢視結果 | [回總報告首頁](index.html) |
