---
title: C02 前門 → api
eyebrow: Guidant AI 資安檢視總報告 · 連線清單
h1: C02 前門 → api
subtitle: guidant-fe → guidant-api，HTTP :8000
lede: 所有業務 API 走的那條線——使用者在畫面上做的每一件事，最後都變成這條線上的一個請求。它承載全產品的功能，也承載 **168 條**掃描問題，佔六頁 STRIDE 不重複條目的三分之二。這一頁回答：這條線**怎麼連**、**哪些功能走它**、它帶來**什麼威脅、駭客怎麼打**、我們**要怎麼防、目前做到哪**。
chips:
  - { text: "必有", kind: plain }
  - { text: "驗 JWT・不驗權限", kind: warn }
  - { text: "威脅 12 種", kind: accent }
  - { text: "掃描命中 168 條", kind: plain }
---

> **這一頁怎麼來的**：[DFD Level 0](../DFD/dfd-level0.html#c02) 把產品運作時的連線編成 C01～C25；[STRIDE 六頁](../STRIDE/S-spoofing.html)每一條問題都標了發生在哪幾條線。這裡以**連線**為單位整理。C02 命中的 168 條太多，不逐條表，改成**十二種攻擊手法**，每種寫駭客怎麼打、得手什麼，底下列全部實例連回 STRIDE 頁。個別問題修了沒不在這頁講。

## 一、連線圖

```{.mermaid cap="C02 — 前門到 api。前門把 /api/1.0 的請求原樣轉給 api；api 入口驗 JWT（你是誰），之後「你能不能做這件事」由每一支端點自己檢查——這是 168 條問題的來源：檢查寫在 400 多支端點裡，漏一支就是一個洞。"}
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB'}}}%%
flowchart LR
    U(["👤 已登入使用者<br/>（任何角色、任何客戶）"])
    FE["guidant-fe<br/>nginx 前門"]
    subgraph API["guidant-api :8000"]
        direction TB
        MW["入口攔截器<br/>記日誌・遮密碼"]
        JWT["驗 JWT<br/>（你是誰）"]
        subgraph EP["400+ 支端點，各自守門"]
            direction LR
            E1["有守門：<br/>專案成員？角色？能力點？"]
            E2["沒守門：<br/>只問有沒有登入"]
        end
        MW --> JWT --> EP
    end
    DB[("guidant-db<br/>RLS 以租戶隔離")]
    U == "C01" ==> FE
    FE == "C02 · /api/1.0 · JWT Bearer" ==> API
    E1 -- "C05" --> DB
    E2 -- "C05 · 同一個租戶內<br/>RLS 擋不住" --> DB
    classDef ext fill:#FBFCFC,stroke:#9AA8AA,stroke-dasharray:3 2
    classDef bad fill:#FDECEC,stroke:#C0392B
    class U ext
    class E2 bad
```

## 二、這條線怎麼連

| 項目 | 現況 |
|---|---|
| **誰 → 誰** | `guidant-fe`（nginx）→ `guidant-api`（Flask／gunicorn）。走 docker 內部網路，api 的 :8000 **不對外開**，只有前門連得到 |
| **協定／埠** | HTTP :8000（內網明文；加密在前門 C01 終止）。路徑固定 `/api/1.0/…`，所有業務路由都掛在這個前綴下 |
| **傳什麼** | 全部業務 API：讀寫專案、問卷、範本、稽核紀錄、系統設定、檔案上傳與下載、匯入匯出、AI 功能。前門轉發時帶 `X-Real-IP`／`X-Forwarded-For`，api 靠這個知道真正來源 |
| **怎麼驗身分** | **JWT（Bearer）**。api 入口驗 token 有效、解出使用者與租戶，寫進 session 變數給資料庫 RLS 用。**但入口只驗「你是誰」，不驗「你能不能做這件事」**——後者由每一支端點自己呼叫守門（`common/authz/` 七個軸：平台管理員、超級管理員、專案角色、能力點、簽章憑證、授權、總部層級） |
| **驗身分之前做的事** | 入口攔截器先記請求日誌、遮密碼（見 [C01](C01-browser-to-frontdoor.html) T2），再驗 JWT |
| **租戶隔離** | 資料庫層 RLS 以 session 變數擋**跨客戶**讀寫。**同一客戶內**的隔離（你是不是這個專案的人）RLS 不管，全靠端點守門 |
| **何時存在** | 必有 |

依據：FE `nginx.onprem.conf`、`common/middleware/app_mw.py`、`common/authz/__init__.py` 決策表、DFD Level 0。

## 三、哪些功能會走這條線

**全部業務功能**。對這條線的威脅分析，功能依「守門的軸」分四群——每群出的問題形狀不同：

| 群 | 功能 | 守門靠什麼 | 威脅的來源 |
|---|---|---|---|
| **① 專案內的讀寫** | 稽核任務、證據、問卷填答、稽核判定、改善計畫、摘要報告、流程 | 「你是不是這個專案的人、什麼角色」——每支端點要自己先查成員資格 | 端點忘了查，或查了 A 動的是 B |
| **② 公司級共用資料** | 合規範本（SSP）、框架、公告、設備清冊、意見回饋、人員名冊 | 能力點（RBAC）或「你是不是這家公司的」 | 只問登入不問能力；查詢條件沒填就回整張表 |
| **③ 系統設定與帳號** | SMTP／LDAP／儲存／日誌轉送設定、個人資料、綁定外部帳號、授權檔 | 總部層級、平台管理員、本人確認 | 層級算錯、把設定連密碼一起回給瀏覽器、改個人資料順手改角色 |
| **④ 匯入匯出與解析** | Excel／Word／PDF／YAML／規則包上傳解析，Excel／Word／PDF 匯出 | 大小上限、格式驗證、輸出跳脫 | 特製檔讓伺服器卡死；使用者的字進了公式或範本語法 |

## 四、這條線會帶來什麼威脅、駭客怎麼打

168 條歸納成**十二種手法**。前提都一樣：**攻擊者有一個有效帳號**（任何客戶的任何員工都算；T6 與 T10 的部分條目連帳號都不用）。每種寫駭客實際的步驟與得手什麼；實例欄是該手法的全部條目，**滑鼠移到編號上顯示標題，點了連回 STRIDE 頁**。

| # | 風險 | 威脅 | 駭客怎麼打 | 得手什麼 | STRIDE | 實例 |
|---|---|---|---|---|---|---|
| T1 | 🟠 高 | **換一個編號，讀到別人專案的東西**（24 條） | ① 用自己的帳號登入，打開任何一個自己的專案，從網址或請求裡看到專案／任務／輪次／報告的編號；② 把編號換成別人的（編號多半是連號或可猜）；③ 端點只檢查「有沒有登入」，不檢查「這個編號是不是你的」，照樣回資料。 | 同一家客戶內其他專案的稽核判定、改善計畫、證據清單、人員配置、報告——嚴重時跨客戶（RLS 沒擋到的查法）。 | [I 資料外洩](../STRIDE/I-information-disclosure.html) | [M02-1](../STRIDE/I-information-disclosure.html#m02-1 "拿到檔案編號就能下載別人的檔案") 🟠、[M06-1](../STRIDE/I-information-disclosure.html#m06-1 "知道一個任務編號就能讀走稽核證明清單") 🟠、[M06-5](../STRIDE/I-information-disclosure.html#m06-5 "知道一個稽核輪次編號就能讀走別人的階段歷程") 🟡、[M06-6](../STRIDE/I-information-disclosure.html#m06-6 "「查目前在哪個階段」用的專案編號和輪次編號兩者不核對") 🟡、[M10-2](../STRIDE/I-information-disclosure.html#m10-2 "換一個編號，就讀到別人專案群組層與控制項層的人員配置") 🟡、[M10-3](../STRIDE/I-information-disclosure.html#m10-3 "不是專案的人直接開專案摘要報告，讀到稽核結論與歷史版本") 🟡、[M10-4](../STRIDE/I-information-disclosure.html#m10-4 "不是這個專案的人，換網址就看到別人專案的稽核判定與改善計畫") 🟠、[M10-22](../STRIDE/I-information-disclosure.html#m10-22 "證據蒐集執行進度只驗登入，換專案編號就看到別人的完成數") ⚪、[M11-1](../STRIDE/I-information-disclosure.html#m11-1 "知道系統安全計畫編號，就能整份下載成 Excel——而且跨客戶") 🟠、[M11-4](../STRIDE/I-information-disclosure.html#m11-4 "範本裡的人員、設備、系統元件、繼承授權與系統特性拿編號就讀得到，而且跨公司") 🟡、[M11-12](../STRIDE/I-information-disclosure.html#m11-12 "可以把別人的程序書掛到自己的控制項，再從回應讀到檔案編號去下載") 🟡、[M12-1](../STRIDE/I-information-disclosure.html#m12-1 "同公司不是這個專案的人，換個網址就看得到稽核判定與改善計畫") 🟠、[M12-4](../STRIDE/I-information-disclosure.html#m12-4 "同一家客戶任何帳號都看得到任何專案的「任務設定樹」") ⚪、[M12-5](../STRIDE/I-information-disclosure.html#m12-5 "非成員知道專案編號就問得出「目前的系統安全計畫」編號與狀態") ⚪、[M20-3](../STRIDE/I-information-disclosure.html#m20-3 "查任務詳細資料收了專案編號卻從頭到尾沒用") 🟡、[M05-2](../STRIDE/I-information-disclosure.html#m05-2 "讀某份問卷的答案不檢查這份問卷是不是你的") 🟠、[M05-6](../STRIDE/I-information-disclosure.html#m05-6 "還原歷史版本時不檢查指定的版本是不是這份問卷的") 🟡、[M10-21](../STRIDE/T-tampering.html#m10-21 "還原摘要報告歷史版本不檢查版本屬於哪份報告") 🟡、[M03-12](../STRIDE/I-information-disclosure.html#m03-12 "查掃描執行紀錄少了「你是不是這個專案的人」這道檢查") 🟡、[M06-17](../STRIDE/I-information-disclosure.html#m06-17 "規劃頁的任務清單不問你是不是這個專案的人") 🟡、[M06-22](../STRIDE/I-information-disclosure.html#m06-22 "「查卡住狀態」誰都能查別的專案") ⚪、[M07-2](../STRIDE/I-information-disclosure.html#m07-2 "舊線查結果、查報表不檢查專案成員，查不到還退回直接讀雲端硬碟") 🟡、[M07-3](../STRIDE/I-information-disclosure.html#m07-3 "舊線工作清單與單筆狀態不檢查專案成員，進度資料不分客戶") 🟡、[M24-2](../STRIDE/I-information-disclosure.html#m24-2 "重建專案雲端資料夾不檢查專案是不是你的，背景還用系統身分載入") 🟠 |
| T2 | 🟠 高 | **送空白查詢，整張表一次撈走**（14 條） | ① 找一支列表查詢端點（專案成員、任務指派、填答歷史、問卷討論）；② 把查詢條件全部留空、或把每頁筆數填極大；③ 底層「條件沒填就不過濾」，一次回整個客戶（或全站）的資料。 | 全公司成員名冊含 email、一萬多筆指派紀錄、所有討論內容。 | [I 資料外洩](../STRIDE/I-information-disclosure.html) | [M05-1](../STRIDE/I-information-disclosure.html#m05-1 "查填答歷史明細不檢查歸屬，送空白請求就整包讀走") 🟠、[M05-3](../STRIDE/I-information-disclosure.html#m05-3 "列出任務問卷不限範圍，送空白請求就回整個客戶的全部") 🟡、[M05-4](../STRIDE/I-information-disclosure.html#m05-4 "列出填答歷史不限範圍") 🟡、[M05-5](../STRIDE/I-information-disclosure.html#m05-5 "問卷討論列表送空查詢就把全公司討論撈回來") 🟡、[M10-1](../STRIDE/I-information-disclosure.html#m10-1 "對專案成員查詢送空白查詢，一次拿到全公司成員名冊") 🟡、[M10-5](../STRIDE/I-information-disclosure.html#m10-5 "對任務指派清單送空白查詢，一次拿到全公司一萬多筆指派紀錄") 🟡、[M10-9](../STRIDE/I-information-disclosure.html#m10-9 "底層「查詢條件全沒填就不過濾」，空白查詢等於回整張表") 🟡、[M10-11](../STRIDE/T-tampering.html#m10-11 "同一個洞從任務與成員管理那邊撈到的一次") 🟡、[M21-2](../STRIDE/I-information-disclosure.html#m21-2 "任何登入帳號都拿得到全站使用者名冊（含電子郵件）") ⚪、[M11-31](../STRIDE/I-information-disclosure.html#m11-31 "從框架版本下載空白範本，附了全公司 email、設備與 IP") ⚪、[M11-40](../STRIDE/I-information-disclosure.html#m11-40 "人員對帳收了公司編號卻沒用，會拿所有客戶的人員來比對") ⚪、[M04-7](../STRIDE/D-denial-of-service.html#m04-7 "一次要求回傳幾筆資料，沒有上限") 🟡、[M19-3](../STRIDE/D-denial-of-service.html#m19-3 "設備清單一頁要顯示幾筆，沒有上限") ⚪、[M12-3](../STRIDE/D-denial-of-service.html#m12-3 "稽核紀錄 Excel 在很後面填一格，系統就從頭一列列讀到那裡") 🟡 |
| T3 | 🟠 高 | **只問登入不問能力，沒被授權的員工直接打網址**（18 條） | ① 畫面上看不到某功能（選單沒給你）；② 從別人的操作或前端程式碼找到那支端點的網址；③ 直接打，端點只驗 JWT 不驗能力點或角色，照樣給。 | 合規範本全文、範本掛的程序書（附檔案編號可下載）、設備清冊、流程範本、AI 儀表板查到的任何資料。 | [I 資料外洩](../STRIDE/I-information-disclosure.html)、[E 權限提升](../STRIDE/E-elevation-of-privilege.html) | [M11-14](../STRIDE/I-information-disclosure.html#m11-14 "沒被授權看合規範本的員工，直接打網址就讀走全公司範本") 🟡、[M11-15](../STRIDE/I-information-disclosure.html#m11-15 "範本的稽核流程圖任何登入帳號都讀得到") 🟡、[M11-16](../STRIDE/I-information-disclosure.html#m11-16 "範本掛了哪些程序書任何人都列得出來，附檔案編號就能下載") 🟡、[M11-17](../STRIDE/I-information-disclosure.html#m11-17 "範本的「稽核目標預設內容」任何登入帳號都讀得到") 🟡、[M11-28](../STRIDE/I-information-disclosure.html#m11-28 "範本的「設備／資訊系統對照」清單任何登入帳號都讀得到") ⚪、[M19-1](../STRIDE/I-information-disclosure.html#m19-1 "設備與資訊系統清冊的讀取只檢查登入、不檢查權限") 🟡、[M17-3](../STRIDE/I-information-disclosure.html#m17-3 "用網址直接開一則公告，完全不做任何檢查") ⚪、[M17-4](../STRIDE/I-information-disclosure.html#m17-4 "公告列表碰到沒有部門的帳號就整個不過濾") ⚪、[M06-11](../STRIDE/I-information-disclosure.html#m06-11 "流程範本的列表與單筆讀取沒有掛權限檢查") ⚪、[M05-11](../STRIDE/I-information-disclosure.html#m05-11 "問卷資料夾列表可以叫出系統刻意隱藏的資料夾") ⚪、[M03-8](../STRIDE/I-information-disclosure.html#m03-8 "權限矩陣取消勾選後，後端八支讀取照樣回全部") ⚪、[M11-13](../STRIDE/E-elevation-of-privilege.html#m11-13 "建立資源庫的入口只驗登入、沒有權限檢查") 🟡、[M15-2](../STRIDE/I-information-disclosure.html#m15-2 "AI 儀表板呼叫的 26 支查詢完全不檢查「你能不能看這筆資料」") 🟡、[M15-3](../STRIDE/I-information-disclosure.html#m15-3 "AI 儀表板查專案清單時把呼叫者當成管理員") 🟡、[M15-7](../STRIDE/E-elevation-of-privilege.html#m15-7 "AI 儀表板生成只檢查有沒有買模組，不檢查角色權限") ⚪、[M17-2](../STRIDE/I-information-disclosure.html#m17-2 "AI 儀表板這條路繞過守門直接讀公告") 🟡、[M14-1](../STRIDE/D-denial-of-service.html#m14-1 "聊天沒有長度上限，也沒有次數限制") 🟡、[M06-2](../STRIDE/S-spoofing.html#m06-2 "流程留言的讀與寫都只檢查有沒有登入") 🟠 |
| T4 | 🟠 高 | **檢查 A、動的是 B——兩個編號不核對**（14 條） | ① 請求帶兩個編號（例如「專案」與「任務」、「範本」與「子項」）；② 端點只檢查第一個是不是你的，第二個不核對是否屬於第一個；③ 第一個填自己的、第二個填別人的，通過檢查後動到別人的資料。 | 改、刪別人專案的任務與文件，把別人的程序書掛到自己控制項再下載。 | [T 竄改資料](../STRIDE/T-tampering.html)、[E 權限提升](../STRIDE/E-elevation-of-privilege.html) | [M06-18](../STRIDE/T-tampering.html#m06-18 "匯入任務 Excel 的確認那步改得到別的專案") 🟡、[M06-19](../STRIDE/R-repudiation.html#m06-19 "甲專案管理人能強制開始乙專案的任務，事件記在甲名下") 🟡、[M06-20](../STRIDE/I-information-disclosure.html#m06-20 "匯出任務 Excel 時，檢查的專案和實際匯出的專案可以是兩個") ⚪、[M06-24](../STRIDE/T-tampering.html#m06-24 "流程圖編輯器存檔時硬刪別人專案的任務") ⚪、[M10-6](../STRIDE/E-elevation-of-privilege.html#m10-6 "指派任務時「專案填自己的、任務填別人的」照樣放行") 🟡、[M10-10](../STRIDE/T-tampering.html#m10-10 "寫入群組層與控制項層成員時不比對歸屬") ⚪、[M10-12](../STRIDE/E-elevation-of-privilege.html#m10-12 "更新任務指派時撈不到既有紀錄就跳過管理者檢查") ⚪、[M11-7](../STRIDE/T-tampering.html#m11-7 "改刪範本子項時，檢查的與動手的不是同一份") 🟡、[M11-11](../STRIDE/T-tampering.html#m11-11 "刪佐證文件時檢查一份、刪的是另一份") 🟡、[M23-7](../STRIDE/T-tampering.html#m23-7 "刪附件時算出了過濾結果卻沒拿來用") ⚪、[M05-10](../STRIDE/T-tampering.html#m05-10 "修改資料夾多塞「已刪除」就繞過刪除守門") 🟡、[M06-21](../STRIDE/I-information-disclosure.html#m06-21 "匯入任務的「驗證」「重新驗證」兩步完全不檢查身分") ⚪、[M12-9](../STRIDE/T-tampering.html#m12-9 "確認匯入稽核結果時佐證照畫面送來的存") ⚪、[M07-1](../STRIDE/I-information-disclosure.html#m07-1 "舊線「預覽證據檔」填任何雲端硬碟檔案編號就把檔案抓回來") 🟠 |
| T5 | 🟠 高 | **角色算寬了：唯讀能改、建立能蓋、子公司管母公司**（22 條） | ① 拿一個低權限角色（唯讀、只有建立權、子公司管理員、專案經理）；② 找到寫入端點，它檢查的角色集合比該有的寬、或檢查的是另一個條件（範本存不存在、歸屬只在改分享時才查）；③ 做本來不該做的事。 | 唯讀角色完成或退回別人的稽核任務、對客戶機器發動掃描；只有建立權的人用整批匯入蓋掉既有範本；子公司改母公司範本。 | [E 權限提升](../STRIDE/E-elevation-of-privilege.html)、[T 竄改資料](../STRIDE/T-tampering.html) | [M06-7](../STRIDE/E-elevation-of-privilege.html#m06-7 "只能看的人可以完成或退回別人的稽核任務") 🟡、[M03-14](../STRIDE/E-elevation-of-privilege.html#m03-14 "唯讀角色可以對客戶機器發動掃描、刪掉執行紀錄") 🟡、[M12-6](../STRIDE/R-repudiation.html#m12-6 "專案經理能改寫、再刪掉稽核人員寫的改善建議") ⚪、[M17-1](../STRIDE/T-tampering.html#m17-1 "改公告、刪公告不問這則是不是你發的") 🟡、[M23-2](../STRIDE/R-repudiation.html#m23-2 "任何員工都能改刪別人的意見回饋並關掉外部問題單") 🟡、[M05-8](../STRIDE/R-repudiation.html#m05-8 "改別人的問卷討論還掛原作者名字，刪除不留痕") 🟡、[M11-5](../STRIDE/T-tampering.html#m11-5 "子公司管理員改得動母公司範本的適用控制項") 🟡、[M11-6](../STRIDE/T-tampering.html#m11-6 "改範本流程圖時，只有順便改分享設定才檢查歸屬") 🟡、[M11-8](../STRIDE/T-tampering.html#m11-8 "範本底下六類附屬資料不問範本是不是你家的") 🟡、[M11-9](../STRIDE/T-tampering.html#m11-9 "用 Excel 批次存範本控制項清單不查歸屬") 🟡、[M11-10](../STRIDE/E-elevation-of-privilege.html#m11-10 "只有建立權限的人走整批匯入就能改掉既有範本") 🟡、[M11-2](../STRIDE/T-tampering.html#m11-2 "用 Excel 蓋掉既有範本，從頭到尾不問你是誰") 🟠、[M11-3](../STRIDE/T-tampering.html#m11-3 "用 Word 蓋掉既有範本，只查範本存不存在") 🟠、[M11-27](../STRIDE/T-tampering.html#m11-27 "刪框架或版本時不檢查還有沒有資源庫在用") 🟡、[M11-30](../STRIDE/I-information-disclosure.html#m11-30 "建資源庫時不看框架版本發佈了沒，草稿也能被複製") ⚪、[M11-33](../STRIDE/T-tampering.html#m11-33 "「重新產生稽核計畫草稿」不看輪次階段") ⚪、[M06-9](../STRIDE/T-tampering.html#m06-9 "流程範本的新增與修改完全不跑檢查") 🟡、[M06-10](../STRIDE/T-tampering.html#m06-10 "起輪次複製範本時不要求範本已發布") 🟡、[M19-2](../STRIDE/T-tampering.html#m19-2 "只有修改權限的人送「停用」就等於刪除") ⚪、[M02-12](../STRIDE/D-denial-of-service.html#m02-12 "刪原廠共用檔時實體先被刪、紀錄卻刪不掉") 🟡、[M24-12](../STRIDE/E-elevation-of-privilege.html#m24-12 "驗證雲端硬碟應用程式憑證只查是不是平台管理員") ⚪、[M10-14](../STRIDE/T-tampering.html#m10-14 "按下去顯示成功卻一筆都沒存的快速設定頁") ⚪ |
| T6 | 🔴 最嚴重 | **帳號與登入本身的洞**（9 條） | 三種路——(a) **自助入口沒確認本人**：存個人資料時夾帶 `role=admin`、綁定外部帳號不驗是本人、雙因子驗證碼無限次猜；(b) **登入的第三方驗證沒接好**：LDAP 匿名能過、Google 登入是空殼；(c) **出廠就帶的後門**：每套安裝同一組最高權限帳號、靜態目錄不用登入就能下載上傳檔、首次開通沒上鎖。 | 把自己升成管理員、接管任何帳號、不用帳號就拿到檔案。 | [S 冒充身分](../STRIDE/S-spoofing.html)、[E 權限提升](../STRIDE/E-elevation-of-privilege.html) | [M13-3](../STRIDE/E-elevation-of-privilege.html#m13-3 "綁定外部帳號不確認是本人") 🟠、[M13-4](../STRIDE/E-elevation-of-privilege.html#m13-4 "存個人資料時順手把自己改成管理員") 🟠、[M13-6](../STRIDE/S-spoofing.html#m13-6 "雙因子驗證碼可以無限次猜") 🟠、[M13-2](../STRIDE/I-information-disclosure.html#m13-2 "公司帳號登入：匿名能過、帳號字串能騙查詢、加密連線不認人") 🟠、[M13-5](../STRIDE/S-spoofing.html#m13-5 "用 Google 登入是沒接通的空殼") 🟠、[M13-1](../STRIDE/E-elevation-of-privilege.html#m13-1 "忘記密碼把重設鑰匙直接回傳給任何人") 🔴、[M17-7](../STRIDE/E-elevation-of-privilege.html#m17-7 "每套安裝都種下同一組最高權限帳號") 🟡、[M24-19](../STRIDE/T-tampering.html#m24-19 "首次開通那一步沒上鎖，連點兩下建出兩家公司") ⚪、[M24-3](../STRIDE/I-information-disclosure.html#m24-3 "使用者上傳的檔案整個資料夾開在 /static/ 下，不用登入就能下載") 🟡 |
| T7 | 🟠 高 | **層級算錯：子公司改全站、他家總部管我家**（4 條） | ① 以子公司管理員、或另一家客戶的總部管理員登入；② 打全公司共用設定的寫入端點（登入規則、帳號目錄、日誌轉送去向）；③ 「誰算總部」的判斷只擋自家子公司、擋不住別家總部，或根本沒分層級。 | 改掉全站登入規則與 LDAP 目錄、把所有客戶的操作日誌轉到自己的伺服器、改暱稱在全公司每份範本埋公式。 | [E 權限提升](../STRIDE/E-elevation-of-privilege.html)、[T 竄改資料](../STRIDE/T-tampering.html) | [M22-1](../STRIDE/E-elevation-of-privilege.html#m22-1 "子公司管理員能改全公司的登入規則與帳號目錄") 🟠、[M22-4](../STRIDE/E-elevation-of-privilege.html#m22-4 "「誰算總部」只擋得住自家子公司，擋不住另一家客戶的總部") 🟠、[M09-1](../STRIDE/I-information-disclosure.html#m09-1 "任何一家客戶的管理員都改得動全系統的日誌轉送去向") 🟠、[M11-21](../STRIDE/E-elevation-of-privilege.html#m11-21 "改自己的暱稱，就在全公司每份範本裡埋公式") 🟡 |
| T8 | 🟠 高 | **回應帶太多：設定連密碼一起回、錯誤訊息吐內部細節**（17 條） | ① 任何登入帳號打「查設定」端點，回應裡儲存空間、郵件伺服器的帳號密碼是明文；② 或打「測試連線」「寄測試信」把目的地改成自己的主機，系統把存著的密碼送過來；③ 或故意送壞資料，錯誤訊息把資料庫原始錯誤、伺服器暫存路徑、密碼鹽值整段回給畫面。 | 儲存與郵件系統的憑證、客戶主機的維運帳密、原廠 AI 金鑰、內部路徑與結構。 | [I 資料外洩](../STRIDE/I-information-disclosure.html) | [M02-5](../STRIDE/I-information-disclosure.html#m02-5 "任何登入者打一支查設定的功能，就拿到雲端儲存的帳號密碼明文") 🟠、[M22-2](../STRIDE/I-information-disclosure.html#m22-2 "任何登入帳號打一支查設定的功能，就拿到檔案儲存的帳號密碼明文") 🟠、[M22-3](../STRIDE/I-information-disclosure.html#m22-3 "儲存設定的密鑰沒在遮蓋名單裡，明文回給瀏覽器") ⚪、[M16-1](../STRIDE/I-information-disclosure.html#m16-1 "寄測試信把存著的郵件密碼送到操作者指定的主機") 🟡、[M07-13](../STRIDE/I-information-disclosure.html#m07-13 "開關一放開，原廠 AI 金鑰就送到客戶指定的伺服器") 🟡、[M03-2](../STRIDE/E-elevation-of-privilege.html#m03-2 "「測試連線」沒檢查權限，按下去就把維運帳密解密送到指定主機") 🟠、[M03-6](../STRIDE/I-information-disclosure.html#m03-6 "「測試連線」要連到哪台主機由呼叫者自己指定") 🟡、[M15-4](../STRIDE/I-information-disclosure.html#m15-4 "AI 儀表板把查到的資料整包送回，夾帶密碼鹽值與超級管理員旗標") 🟡、[M04-12](../STRIDE/I-information-disclosure.html#m04-12 "共用的「資料轉成回覆內容」工具資料上有什麼就吐什麼") ⚪、[M05-12](../STRIDE/I-information-disclosure.html#m05-12 "問卷資料夾列表把資料庫原始錯誤整句吐回畫面") ⚪、[M11-22](../STRIDE/I-information-disclosure.html#m11-22 "框架 PDF 解析失敗時把原始錯誤訊息整段回給前端") 🟡、[M11-32](../STRIDE/I-information-disclosure.html#m11-32 "Word 打不開時錯誤訊息帶出伺服器暫存檔路徑") ⚪、[M24-16](../STRIDE/D-denial-of-service.html#m24-16 "首次安裝精靈設定碼塞中文或特殊字元，伺服器回 500") ⚪、[M24-17](../STRIDE/D-denial-of-service.html#m24-17 "匯出診斷包時一邊帶時區一邊不帶，程式當掉回 500") ⚪、[M04-1](../STRIDE/I-information-disclosure.html#m04-1 "登入密碼與通行證原文寫進紀錄檔與資料庫") 🟠、[M04-3](../STRIDE/I-information-disclosure.html#m04-3 "密碼裡有雙引號就只遮一半") 🟡、[總表#145](../STRIDE/D-denial-of-service.html#r145 "公告查無此筆對空值設值、沒有登入身分時建立公告崩潰") ⚪ |
| T9 | 🟠 高 | **使用者的字變成程式：公式、範本語法、網頁、AI 指令**（14 條） | ① 在任何會被匯出或顯示的欄位（暱稱、描述、意見回饋、規則包）填特製內容：Excel 公式 `=cmd|…`、Word 範本語法 `{{…}}`、網頁程式、換行夾偽造日誌、對 AI 的指令；② 等別人匯出 Excel／Word、點預覽、或 AI 儀表板處理那段字；③ 內容在對方的電腦、我們的伺服器、或 AI 的判斷裡被當成指令執行。 | 在稽核人員電腦執行程式、讓伺服器替人連內網、往客戶監控系統塞假日誌、誘導 AI 選任何查詢。 | [T 竄改資料](../STRIDE/T-tampering.html)、[E 權限提升](../STRIDE/E-elevation-of-privilege.html) | [M03-1](../STRIDE/E-elevation-of-privilege.html#m03-1 "客戶上傳的檢測規則包會被外部工具當成程式碼執行") 🟠、[M02-4](../STRIDE/E-elevation-of-privilege.html#m02-4 "上傳的網頁檔，別人點預覽時被當成程式執行") 🟠、[M10-20](../STRIDE/I-information-disclosure.html#m10-20 "摘要報告匯出 PDF 時放行 SVG 插圖，伺服器會替人去連內網") 🟡、[M09-2](../STRIDE/E-elevation-of-privilege.html#m09-2 "不必登入就能在操作日誌匯出檔裡種公式") 🟠、[M21-1](../STRIDE/E-elevation-of-privilege.html#m21-1 "意見回饋匯出檔可以被種公式") 🟠、[M11-18](../STRIDE/T-tampering.html#m11-18 "匯出 Word 時使用者的字被當成範本語法") 🟡、[M11-19](../STRIDE/E-elevation-of-privilege.html#m11-19 "控制項現況 Excel 的描述會被寫成公式") 🟡、[M11-20](../STRIDE/E-elevation-of-privilege.html#m11-20 "計畫內容裡的公式，在別人下載範本 Excel 時執行") 🟡、[M06-26](../STRIDE/E-elevation-of-privilege.html#m06-26 "匯出任務 Excel 時欄位被當成公式") ⚪、[M06-27](../STRIDE/S-spoofing.html#m06-27 "通知信把暱稱原樣塞進信件，可放釣魚連結") ⚪、[M09-4](../STRIDE/R-repudiation.html#m09-4 "在欄位裡塞換行，就能往客戶監控系統塞偽造日誌") 🟡、[M15-1](../STRIDE/E-elevation-of-privilege.html#m15-1 "打字就能誘導 AI 儀表板選中任何一支查詢") 🟠、[M07-4](../STRIDE/I-information-disclosure.html#m07-4 "舊版證據分類的雲端硬碟搜尋條件用字串拼接") 🟡、[M24-14](../STRIDE/I-information-disclosure.html#m24-14 "依名稱找雲端資料夾時沒處理反斜線") ⚪ |
| T10 | 🟠 高 | **特製檔或請求讓伺服器卡死**（20 條） | ① 做一份幾 KB 的特製檔（壓縮炸彈、幾萬個空白的 Word、一百萬個數字的 Excel 說明頁、特製 YAML、頁數極多的 PDF、永遠算不完的流程圖）；② 從匯入端點上傳，或打「檢查流程圖」「重新解析」這類任何登入者都能打、不限大小的端點；③ 解析時記憶體撐爆或比對卡住，處理程序全被占住。 | 讓整個產品對所有客戶停止回應（其中 M04-15 連帳號都不用）。 | [D 讓服務停擺](../STRIDE/D-denial-of-service.html) | [M04-15](../STRIDE/D-denial-of-service.html#m04-15 "不必登入，送一個特製內容的請求就讓整個產品停止回應") 🟠、[M06-3](../STRIDE/D-denial-of-service.html#m06-3 "一張特製的流程圖讓伺服器永遠算不完") 🟠、[M06-4](../STRIDE/D-denial-of-service.html#m06-4 "「檢查流程圖」任何登入者都能打，而且不限大小") 🟡、[M06-8](../STRIDE/D-denial-of-service.html#m06-8 "一筆空白內容的流程範本讓所有人的清單頁一直出錯") 🟡、[M06-23](../STRIDE/D-denial-of-service.html#m06-23 "匯入任務的 Excel 沒有上傳檢查、整份攤開在記憶體") 🟡、[M03-3](../STRIDE/D-denial-of-service.html#m03-3 "網址型規則包完全繞過壓縮檔的三道上限") 🟡、[M03-4](../STRIDE/D-denial-of-service.html#m03-4 "規則包「最多一萬個檔」的上限對 zip 形同虛設") 🟡、[M03-10](../STRIDE/D-denial-of-service.html#m03-10 "手動重新解析無條件開一條背景工作，可以把主機打掛") 🟡、[M03-11](../STRIDE/D-denial-of-service.html#m03-11 "換掃描工具時舊的超大網段原封不動跟過去") 🟡、[M11-23](../STRIDE/D-denial-of-service.html#m11-23 "系統安全計畫的 Excel 匯入只量上傳檔、不量解開後多大") 🟡、[M11-24](../STRIDE/D-denial-of-service.html#m11-24 "系統安全計畫的 Word 匯入同樣只量上傳檔大小") 🟡、[M11-25](../STRIDE/D-denial-of-service.html#m11-25 "Excel「說明」頁填一百萬個數字，版本號比對就卡住") 🟡、[M11-26](../STRIDE/D-denial-of-service.html#m11-26 "一份幾 KB 的特製 Word 讓系統安全計畫匯入卡到逾時") 🟡、[M11-34](../STRIDE/D-denial-of-service.html#m11-34 "幾 KB 的特製 YAML 範本讓伺服器展開到當掉") ⚪、[M11-35](../STRIDE/D-denial-of-service.html#m11-35 "範本匯入檢核送一格很長的怪字串，佔住處理程序兩分鐘") ⚪、[M11-36](../STRIDE/D-denial-of-service.html#m11-36 "頁數極多的 CMMC PDF 讓解析時記憶體撐爆") ⚪、[M11-37](../STRIDE/D-denial-of-service.html#m11-37 "PDF 裡一行超長的字讓「是不是目錄」的比對卡住") ⚪、[M12-2](../STRIDE/D-denial-of-service.html#m12-2 "稽核計畫 Word 匯入的壓縮炸彈") 🟡、[M12-8](../STRIDE/D-denial-of-service.html#m12-8 "稽核計畫 Word 塞幾萬個空白，解析比對卡到逾時") ⚪、[M18-2](../STRIDE/D-denial-of-service.html#m18-2 "授權檔驗章之前就先解壓縮，而且沒有上限") 🟠 |
| T11 | 🟠 高 | **繞過商務授權**（6 條） | ① 客戶自己上傳舊授權檔、或拿開發環境簽的授權；② 或等過期唯讀的縫（排程一天一次、代理程式網址整段放行、問卷即時填答不經檢查）；③ 或選單反灰但直接打網址。 | 停權復權、過期照用、沒買的模組照用。受損的是原廠收入。 | [E 權限提升](../STRIDE/E-elevation-of-privilege.html) | [M18-1](../STRIDE/E-elevation-of-privilege.html#m18-1 "被停權的客戶自己上傳舊授權檔就能復權") 🟠、[M18-7](../STRIDE/S-spoofing.html#m18-7 "三個環境的公鑰並列，開發環境簽的照正式也認") 🟡、[M18-9](../STRIDE/T-tampering.html#m18-9 "同一張授權檔可能被兩家客戶同時用上") ⚪、[M18-11](../STRIDE/E-elevation-of-privilege.html#m18-11 "授權過期轉唯讀只靠每天一次的排程") ⚪、[M18-13](../STRIDE/E-elevation-of-privilege.html#m18-13 "過期唯讀的兩個縫：代理程式網址整段放行、問卷即時填答不經檢查") ⚪、[M05-14](../STRIDE/E-elevation-of-privilege.html#m05-14 "沒買問卷模組，直接打網址照樣能用「填答」那一半") ⚪ |
| T12 | 🟠 高 | **身分與紀錄對不上：沒身分時隔離關掉、日誌記錯人**（6 條） | ① 讓請求在「沒有登入身分」的狀態下進到業務邏輯（背景工作、某些例外路徑），客戶隔離整個關掉；② 或把網址加長讓這次操作不進日誌、把來源 IP 欄位自填、操作者名稱由呼叫端自填。 | 跨客戶讀寫、事後查不到是誰做的。 | [R 事後無法追查](../STRIDE/R-repudiation.html)、[E 權限提升](../STRIDE/E-elevation-of-privilege.html) | [M04-2](../STRIDE/E-elevation-of-privilege.html#m04-2 "沒有登入身分時，客戶資料隔離整個關掉") 🟠、[M09-6](../STRIDE/R-repudiation.html#m09-6 "把網址加長，這次操作就不會出現在操作日誌") 🟡、[M09-7](../STRIDE/R-repudiation.html#m09-7 "操作日誌的來源 IP 全記成前端代理伺服器") ⚪、[M08-7](../STRIDE/R-repudiation.html#m08-7 "防竄改旁證裡的來源 IP 讀的是用戶端可填的欄位") ⚪、[M06-12](../STRIDE/R-repudiation.html#m06-12 "推進或退回階段時，顯示的操作者名稱由呼叫端自填") ⚪、[M21-3](../STRIDE/D-denial-of-service.html#m21-3 "沒有部門的一般使用者送意見回饋必定失敗、畫面不給理由") 🟡 |

**十二種手法的共同點**：T1～T7、T12 共 111 條都是同一件事——**入口只驗「你是誰」，「你能不能做這件事」寫在 400 多支端點裡各自為政，漏一支就是一個洞**。T8～T10 是另一件事——**端點把使用者給的東西（檔案、字串、查詢條件）當成可信的，沒有統一的上限與跳脫**。這兩個特性是這條線的本質，不是某支程式的 bug。

## 五、我們要怎麼防、目前做到哪

對應十二種威脅，防線分九條。D1～D7 直接對應掃描抓到的手法；**標 ◇ 的是依這條線的特性補的標準防線，掃描範圍沒涵蓋**。「目前」欄寫程式裡**實際有的機制**；⚠️ 表示只靠慣例或只守到局部。

| # | 防線 | 擋哪種威脅 | 目前做到哪 |
|---|---|---|---|
| D1 | **資源域守門統一走 `common/authz/`，不自己寫**。任何帶資源編號的端點，先 resolve 資源、再查呼叫者與資源的關係（專案成員／角色／歸屬），用決策表選對的軸 | T1、T4、T5 | ✅ FR-048 已建七軸決策表與 canonical 實作，舊四套路徑改 deprecated shim，守衛測試擋新引用。⚠️ 是「新 code 一律用」的規範，**既有 400 多支端點沒有全面回掃**——168 條裡 T1／T4／T5 的 60 條就是回掃抓到的，掃描範圍外的端點不保證 |
| D2 | **兩個編號必核對歸屬**。請求帶父子兩個編號時，守門要驗子屬於父，不能只驗父 | T4 | ⚠️ 逐支修，沒有框架層強制。`assert_project_role` 系列有做 control→group→project 的 fallback，但「任務屬於專案」這類核對仍靠端點自己寫 |
| D3 | **列表查詢條件沒填就拒絕，每頁筆數有上限**。底層 repo 不接受空條件回整張表 | T2 | ⚠️ 逐支修（M10-9 是底層通則，修了那一支）。沒有 repo 層的全域守則，新加的列表端點可能再犯 |
| D4 | **能力點（RBAC）掛在 route decorator，看不到的功能網址也打不到**。選單反灰與端點守門用同一張能力點表 | T3、T11 | ✅ `@require_capability` 軸④已有，super_admin 旁路。⚠️ 能力點 seed 不全（決策表註明「未 seed 前過渡用 require_super_admin」），哪些端點已掛、哪些還沒，沒有清單 |
| D5 | **總部層級與租戶隔離有單一判斷點**。「誰算總部」只有一個函式；「沒有登入身分」時 RLS 必須是**最嚴**而不是關掉 | T7、T12 | ✅ 軸⑦ `require_tenant_hq()` 已建（CM-2401 補了三組共用設定）。✅ M04-2 無身分時隔離已改成拒絕。⚠️ 哪些端點該掛軸⑦，靠人判斷 |
| D6 | **回應 schema 白名單，不回不該回的欄位**。設定類回應一律遮密鑰；錯誤訊息只回代碼，原始例外只進日誌 | T8 | ✅ 遮密碼名單有（`mark_password`），設定讀取三組已補守門。⚠️ 遮蓋靠「名單」，新欄位沒加進名單就漏（M22-3 就是）；錯誤訊息回畫面的習慣沒有框架層攔截 |
| D7 | **所有使用者輸入在出口跳脫**：匯出 Excel 時公式前綴加 `'`、Word 範本語法轉義、日誌欄位去換行、對 AI 的輸入與工具選擇分離 | T9 | ✅ 逐條修了（Excel 公式、Word 語法、日誌換行、AI 工具選擇）。⚠️ 跳脫寫在各匯出點，沒有共用的「輸出工具」統一處理，新匯出功能要記得 |
| D8 ◇ | **解析前先量大小、解析時限資源**。所有匯入與解析端點：上傳檔大小、解開後大小、檔案數、解析逾時與記憶體上限，用同一套常數 | T10 | ✅ 逐條修了 20 條，各自加了上限。⚠️ 上限散在各模組，沒有一處「所有解析端點必過」的守門；前門不限大小（C01 D7） |
| D9 ◇ | **端點守門覆蓋率用程式產清單、不靠記憶**：每支路由掛了哪個軸、哪些只驗 JWT，定期產表對照 | 全部 | ⚠️ **沒有**。`scripts/deliverables/collect_routes.py` 能列路由，但沒有「掛了哪個守門」這一欄。這是把 D1～D5 從「規範」變「機制」的那一步 |

**最該補的一步**：D9。168 條裡 T1～T7 共 100 多條，全是「某支端點漏了守門」——這種病不會因為修了 168 支就好，會在下一支新端點再長出來。產一份「路由 × 守門軸」的清單，讓漏掛的端點在 review 時就看得見，比再掃一輪便宜得多。

## 六、依這些防線，掃描還沒看過的地方

- **路由守門覆蓋表**（D9）：掃描是人讀程式抓的，168 條之外有沒有漏網不知道。用程式列出全部路由與各自掛的守門軸，「只驗 JWT」的那些逐一判定該不該。
- **能力點 seed 清單**（D4）：哪些 `<resource>.manage` 已 seed、哪些端點還在用 `require_super_admin()` 過渡。
- **repo 層空條件行為**（D3）：M10-9 修了一支底層，其他 repo 的 `query` 方法遇到空條件怎麼處理，沒有盤過。

---

*依據：STRIDE 六頁信任邊界連線標記（CM-2403／2404 驗收後版本）、`common/authz/__init__.py` 決策表、`common/middleware/app_mw.py`、FE `nginx.onprem.conf`、DFD Level 0。分組是首腦依標題與「駭客怎麼打」歸納的，同一條若兩種手法都沾，歸主要那種。*
