---
title: SR-06 祕密管理
eyebrow: Guidant AI 資安檢視總報告 · 安全需求（SR）
h1: SR-06 祕密管理
subtitle: 加密落庫、寫出去就遮、解密後只留記憶體
lede: 祕密（密碼、金鑰、通行證、webhook 網址）只在「用的那一刻」以明文存在，其餘時間都是密文或不存在。這一章 **8 條**：落庫加密與讀取遮罩、日誌與診斷包遮蔽、解密後只留記憶體、位址與金鑰綁在一起、服務帳號最小權限、備份同等保護。4 條有掃描實例、4 條是標準做法。
chips:
  - { text: "8 條", kind: accent }
  - { text: "掃描驗證 4", kind: ok }
  - { text: "標準做法 4", kind: plain }
---

> 讀法見[總表](SR-00-overview.html)。每條六欄：要求／為什麼／適用連線／對應威脅／驗證方式／來源。現況不在這裡，看[符合性矩陣](SR-matrix.html)。

## 這一章管什麼

系統替客戶保管三類祕密：**整合憑證**（郵件、AI、雲端硬碟、問題追蹤、聊天通知）、**維運帳密**（掃描用的 SSH／WinRM 與工具權杖）、**服務自己的鑰匙**（資料庫、Redis、授權簽發站的 API 通行證）。祕密外洩的路只有幾條：落在資料庫裡的明文、寫進日誌與診斷包、被騙去送到別人的主機、備份檔被拿走。掃描抓到的實例幾乎全是「明文多留了一份」或「連不上時把整組設定寫進紀錄」這兩種形狀。

| # | 要求 | 來源 |
|---|---|---|
| SR-06.1 | 整合憑證加密落庫、讀取遮罩，不以明文回給瀏覽器 | 標準做法 |
| SR-06.2 | 祕密在寫出去的那一刻就遮掉 | 掃描驗證 |
| SR-06.3 | 存著的密碼只能跟著存著的主機走 | 掃描驗證 |
| SR-06.4 | 解密後的帳密只留記憶體 | 掃描驗證 |
| SR-06.5 | 位址跟著金鑰走，兩者只能來自同一層 | 掃描驗證 |
| SR-06.6 | 服務帳號最小權限，密碼由安裝程式產生 | 標準做法 |
| SR-06.7 | 簽發站 API 通行證與 DB 密碼同級保管並輪替 | 標準做法 |
| SR-06.8 | 備份與匯出受同等保護 | 標準做法 |

---

## SR-06.1 整合憑證加密落庫、讀取遮罩，不以明文回給瀏覽器 {#sr-06-1}

| 欄位 | 內容 |
|---|---|
| **要求** | 整合憑證——SMTP 密碼、AI 金鑰、Drive 密鑰、GitLab／GitHub 通行證、Discord webhook 網址與 Telegram bot token、工具帳密——**必須**加密後才寫進資料庫；讀取 API **必須**遮罩（不回明文，欄位只回「已設定」）；寫入時使用者沒改該欄，伺服器**必須**從既有列補回，不得把遮罩值當新值存下 |
| **為什麼** | 資料庫備份、唯讀帳號、診斷包任何一條路被拿走，明文欄位就直接是可用的公司郵件帳密、問題單通行證、頻道發話權，不必破解任何東西 |
| **適用連線** | [C10](../connections/C10-api-to-smtp.html) api → 客戶 SMTP、[C15](../connections/C15-api-to-issue-tracker.html) api → 問題追蹤（GitLab／GitHub）、[C16](../connections/C16-api-to-chat-webhook.html) api → 聊天 webhook（Discord／Telegram）；推及：[C13](../connections/C13-api-to-external-ai.html) api → 外部 AI（AI 金鑰）、[C14](../connections/C14-api-to-google-drive.html) api → Google Drive（Drive 密鑰） |
| **對應威脅** | C16 [T3 webhook 網址外流後冒充系統發話](../connections/C16-api-to-chat-webhook.html)（無掃描實例） |
| **驗證方式** | 直接查資料庫存放各整合憑證的欄位，內容必須是密文而非可讀字串；以管理員身分呼叫各整合的讀取 API，回應不得含任何憑證明文；不改密碼欄、只改別的欄位存檔，再用該憑證實際連線必須仍成功（證明補回有效） |
| **來源** | 標準做法：C10 D5◇、C15 D3◇、C16 D3◇ |

## SR-06.2 祕密在寫出去的那一刻就遮掉 {#sr-06-2}

| 欄位 | 內容 |
|---|---|
| **要求** | 祕密**必須**在寫出去的那一刻就遮掉：日誌的三個出口（請求標頭、請求內容、回應內容）**必須**接同一支遮蔽函式，且能處理跳脫字元（密碼含雙引號不得只遮一半）；整合設定的失敗紀錄**只記**位址與錯誤類別，**不得**把含密碼的設定物件格式化進日誌；診斷包與日誌轉送（SIEM）**必須**經同一套遮蔽；登入權杖（含即時連線交握裡的）**不得**進任何紀錄 |
| **為什麼** | 日誌、診斷包、轉送紀錄三條路都會離開主機。祕密一旦寫進去，經手診斷包的人、能看紀錄的維運、收轉送的 SIEM 都能直接拿到登入密碼、可冒用的通行證或公司郵件帳密；密碼越強（含特殊字元）越容易被只認簡單格式的遮蔽漏掉 |
| **適用連線** | [C05](../connections/C05-api-to-database.html) api → 資料庫、[C10](../connections/C10-api-to-smtp.html) api → 客戶 SMTP、[C03](../connections/C03-frontdoor-to-socketio.html) 前門 → socketio、[C12](../connections/C12-api-to-siem.html) api → 客戶 SIEM（日誌轉送）；推及：[C13](../connections/C13-api-to-external-ai.html) api → 外部 AI（AI 金鑰與對話內容進日誌前） |
| **對應威脅** | C05 [T4 祕密以明文落在資料庫裡：密碼、通行證、主機帳密**（4 條）](../connections/C05-api-to-database.html) 🟠、C10 [T3 寄信失敗把密碼寫進紀錄](../connections/C10-api-to-smtp.html) 🟡、C03 [T4 逐封包紀錄把交握裡的登入權杖寫進容器紀錄，再隨診斷包出門](../connections/C03-frontdoor-to-socketio.html) 🟡、C12 [T1 在路上側錄全部日誌](../connections/C12-api-to-siem.html) 🟡 |
| **驗證方式** | 用含雙引號與反斜線的密碼登入，查操作日誌表與 `app.log`，密碼不得以任何形式出現；讓郵件伺服器連不上並觸發寄信失敗，日誌只能有主機、埠、錯誤類別；產一份診斷包與一筆轉送紀錄，全文搜尋 `password`、`Authorization`、權杖前綴必須無命中；即時連線正式環境的逐封包紀錄必須關閉 |
| **來源** | 掃描驗證：C05 D4（實例 [M04-1](../STRIDE/I-information-disclosure.html#m04-1)、[M03-9](../STRIDE/I-information-disclosure.html#m03-9)、[M04-3](../STRIDE/I-information-disclosure.html#m04-3)、[M16-2](../STRIDE/I-information-disclosure.html#m16-2)）、C10 D3（實例 [M16-2](../STRIDE/I-information-disclosure.html#m16-2)）、C03 D4（實例 [M24-5](../STRIDE/I-information-disclosure.html#m24-5)）；標準做法：C12 D4◇ |

## SR-06.3 存著的密碼只能跟著存著的主機走 {#sr-06-3}

| 欄位 | 內容 |
|---|---|
| **要求** | 所有「測試連線」類功能，若畫面送來的主機位址或埠與存著的不同，密碼欄沒重新輸入時**必須**拒絕（回 400），**不得**沿用存著的那組密碼去連新位址；此規則**必須**涵蓋郵件、LDAP、日誌轉送、Discord、Telegram、問題追蹤、AI 服務每一支測試按鈕 |
| **為什麼** | 有設定頁權限的人把位址改成自己的機器、密碼欄留空、按「測試」，系統就拿存著的真密碼去連他的機器，帳密當場到手，可冒公司名義對外寄信 |
| **適用連線** | [C10](../connections/C10-api-to-smtp.html) api → 客戶 SMTP；推及：[C11](../connections/C11-api-to-ldap.html) api → 客戶 LDAP／AD（LDAP 測試連線）、[C12](../connections/C12-api-to-siem.html) api → 客戶 SIEM（日誌轉送）（日誌轉送測試）、[C13](../connections/C13-api-to-external-ai.html) api → 外部 AI（AI 服務測試）、[C15](../connections/C15-api-to-issue-tracker.html) api → 問題追蹤（GitLab／GitHub）（問題追蹤測試）、[C16](../connections/C16-api-to-chat-webhook.html) api → 聊天 webhook（Discord／Telegram）（聊天通知測試） |
| **對應威脅** | C10 [T1 把存著的密碼騙到自己的主機](../connections/C10-api-to-smtp.html) 🟡 |
| **驗證方式** | 對每支測試連線端點：保持密碼欄空白、把主機改成另一個位址送出，必須回 400 且對方機器收不到任何連線；主機不變、密碼欄空白送出，必須成功（沿用存著的） |
| **來源** | 掃描驗證：C10 D1（實例 [M16-1](../STRIDE/I-information-disclosure.html#m16-1)） |

## SR-06.4 解密後的帳密只留記憶體 {#sr-06-4}

| 欄位 | 內容 |
|---|---|
| **要求** | 解密後的維運帳密與工具權杖**只能**存在記憶體：派工單落庫時**不得**含明文，agent 領單時才當場解密；解密值**不得**落實體磁碟、**不得**進命令列參數、**不得**進任何日誌、**不得**寫回任何資料表；派工單另**必須**限租戶查詢 |
| **為什麼** | 派工單與操作日誌一旦留一份明文，每次掃描就在資料庫留下客戶正式機房的可用密碼且不會清理；命令列與暫存檔則讓同一台主機上的任何人看得到 |
| **適用連線** | [C20](../connections/C20-agent-to-frontdoor.html) agent → 主系統前門、[C23](../connections/C23-agent-to-target-host.html) agent → 受檢主機、[C23a](../connections/C23a-agent-to-tool-servers.html) agent → 工具伺服器、[C09](../connections/C09-api-to-worker.html) api → worker（背景工作）；推及：[C21](../connections/C21-api-to-agent-dataplane.html) api → agent 資料面（:8443）（測試連線把帳密送 agent） |
| **對應威脅** | C20 [T4 領工作時要用的祕密，在資料庫裡多留了一份明文](../connections/C20-agent-to-frontdoor.html) 🟡、C23 [T2 假冒受檢主機，接走帳密**（SSH 不驗指紋／WinRM 明文）](../connections/C23-agent-to-target-host.html)（無掃描實例）、C23 [T3 受檢主機被入侵後，反過來打代理程式](../connections/C23-agent-to-target-host.html)（無掃描實例）、C23a [T1 假冒工具伺服器，接走管理員帳密](../connections/C23a-agent-to-tool-servers.html)（無掃描實例） |
| **驗證方式** | 派一次掃描後查派工單表與操作日誌表，參數欄位不得出現任何明文密碼或權杖；在 agent 主機上掃描期間以 `ps` 與檢視暫存目錄，命令列與檔案中不得出現帳密；以 A 租戶身分查 B 租戶的派工單必須查無 |
| **來源** | 掃描驗證：C20 D4（實例 [M03-9](../STRIDE/I-information-disclosure.html#m03-9)）；標準做法：C23 D2◇、C23a D3◇、C09 D8◇ |

## SR-06.5 位址跟著金鑰走，兩者只能來自同一層 {#sr-06-5}

| 欄位 | 內容 |
|---|---|
| **要求** | 外部 AI 服務的 `base_url` 與金鑰**必須**來自同一層設定：原廠金鑰**只配**原廠（或官方）位址；新租戶建立時**不得**抄原廠金鑰；租戶沒設位址時**必須**明示官方位址、**不得**讀環境變數補位；不得出現「租戶填位址、原廠出金鑰」的混搭 |
| **為什麼** | 客戶管理員把服務位址改成自己的機器、金鑰欄留空，系統找不到客戶金鑰就拿原廠的，原廠金鑰放在授權標頭直接送到攻擊者手上，可拿去燒原廠的帳 |
| **適用連線** | [C13](../connections/C13-api-to-external-ai.html) api → 外部 AI |
| **對應威脅** | C13 [T1 把原廠金鑰騙到自己的伺服器](../connections/C13-api-to-external-ai.html) 🟡 |
| **驗證方式** | 以租戶管理員身分把 AI 服務位址改成自己控制的測試伺服器、金鑰欄留空，觸發一次分類；測試伺服器收到的請求不得帶原廠金鑰，系統必須回「未設定金鑰」錯誤；新建租戶後查其設定，金鑰欄必須為空 |
| **來源** | 掃描驗證：C13 D1（實例 [M07-13](../STRIDE/I-information-disclosure.html#m07-13)） |

## SR-06.6 服務帳號最小權限，密碼由安裝程式產生 {#sr-06-6}

| 欄位 | 內容 |
|---|---|
| **要求** | 資料庫服務容器**只持**無特權帳號，管理帳號**只在**建庫與升級時使用；資料庫埠**不得**映射到主機；Redis 每個行程**必須**用自己的帳號，只開它需要的指令與 key 前綴（不得給 `+@all ~*`）；S3 埠**必須**只綁本機且金鑰必填；所有服務密碼**必須**由安裝程式產生，**不得**寫死在程式、**不得**進 image、**不得**進版控 |
| **為什麼** | 服務帳號權限過大時，攻下任一容器就等於拿到整個資料層：能繞過租戶隔離、刪掉雙因子失敗計數與節流計數、對所有 key 讀寫；密碼寫死則所有客戶共用同一把 |
| **適用連線** | [C05](../connections/C05-api-to-database.html) api → 資料庫、[C06](../connections/C06-api-to-redis.html) api → Redis、[C22](../connections/C22-agent-to-seaweedfs.html) agent → SeaweedFS；推及：[C07](../connections/C07-api-to-file-storage.html) api → 檔案儲存（物件儲存金鑰同屬此類） |
| **對應威脅** | C06 [T2 拿到 Redis 帳密後歸零節流計數、解除雙因子的猜測上限](../connections/C06-api-to-redis.html)（無掃描實例）、C06 [T3 往推播佇列寫假訊息，或在別人的 AI 對話脈絡裡塞字](../connections/C06-api-to-redis.html)（無掃描實例）、C22 [T2 金鑰或埠外露，同網段的人直接讀整桶](../connections/C22-agent-to-seaweedfs.html)（無掃描實例） |
| **驗證方式** | 以各服務容器內實際使用的帳號連資料庫，嘗試建表、改其他租戶資料、讀系統目錄必須被拒；以 socketio 的 Redis 帳號嘗試刪節流 key 必須被拒；從主機外部連資料庫埠與 :8333 必須連不上；對 image 與版控全文搜尋已知預設密碼必須無命中，兩台新安裝的密碼必須不同 |
| **來源** | 標準做法：C05 D8◇、C06 D3◇、C22 D1◇ |

## SR-06.7 簽發站 API 通行證與 DB 密碼同級保管並輪替 {#sr-06-7}

| 欄位 | 內容 |
|---|---|
| **要求** | 原廠對授權簽發站的 `X-API-Token`**必須**與資料庫密碼同級保管：不進版控、不進 image、不進日誌；**必須**有輪替機制，輪替後舊通行證**必須**立即失效；通行證**不得**隨出貨包交給客戶環境 |
| **為什麼** | 通行證外流時，攻擊者可冒原廠身分走後台請照那條路，簽出任意授權 |
| **適用連線** | [C18](../connections/C18-api-to-license-center.html) api → 授權簽發站 |
| **對應威脅** | 無掃描實例（標準做法） |
| **驗證方式** | 輪替通行證後，用舊通行證呼叫簽發站後台 API 必須被拒；對出貨 image、安裝包與版控全文搜尋通行證值必須無命中；日誌中不得出現該標頭值 |
| **來源** | 標準做法：C18 D6◇ |

## SR-06.8 備份與匯出受同等保護 {#sr-06-8}

| 欄位 | 內容 |
|---|---|
| **要求** | 資料庫備份**必須**加密，或至少限權（僅服務擁有者可讀）並放在資料目錄之外不隨意複製；回廠診斷包**必須**經與日誌相同的遮蔽（見 SR-06.2）；備份與診斷包的產出、取用**必須**有紀錄 |
| **為什麼** | 祕密就算在線上都加了密，備份檔若是明文，拿到備份的人（含經手廠商、離職維運）繞過所有應用層保護直接讀到全部資料 |
| **適用連線** | [C05](../connections/C05-api-to-database.html) api → 資料庫；推及：[C07](../connections/C07-api-to-file-storage.html) api → 檔案儲存（物件儲存備份同理） |
| **對應威脅** | C05 [T4 祕密以明文落在資料庫裡：密碼、通行證、主機帳密**（4 條）](../connections/C05-api-to-database.html) 🟠 |
| **驗證方式** | 取一份新產的備份，不用金鑰直接 `strings` 搜尋 `password`、`secret` 必須無命中，或檔案權限只允許服務擁有者；對診斷包全文搜尋祕密格式必須無命中 |
| **來源** | 標準做法：C05 D9◇ |

---

*來源：[連線頁](../connections/C01-browser-to-frontdoor.html)的防線（D）；去重對照在 `requirements/_drafts/D-to-SR.md`。*
