---
title: C24 agent → 規則包網址
eyebrow: Guidant AI 資安檢視總報告 · 連線清單
h1: C24 代理程式 → 規則包網址（url 型檢測基準，HTTPS）
lede: 客戶用「網址」建檢測基準時，派掃描的代理程式自己去那個網址把規則包抓下來、交給檢測引擎執行的那條線。規則包是**程式**（InSpec 的 Ruby DSL），抓到什麼就跑什麼。雲端那頭已經先抓過一次、算了指紋（[C19](../DFD/dfd-level0.html#c19)），**但代理程式這頭沒有拿那個指紋來比對**。這一頁回答：這條線**怎麼連**、**哪些功能走它**、它帶來**什麼威脅、駭客怎麼打**、我們**要怎麼防、目前做到哪**。
chips:
  - { text: "url 型基準才有", kind: plain }
  - { text: "抓到什麼就執行・不比指紋", kind: warn }
  - { text: "威脅 3 種", kind: accent }
  - { text: "掃描命中 1 條", kind: plain }
---

> **這一頁怎麼來的**：[DFD Level 0](../DFD/dfd-level0.html#c24) 把產品運作時的連線編成 C01～C25；[STRIDE 六頁](../STRIDE/S-spoofing.html)每一條問題都標了發生在哪幾條線。這裡以**連線**為單位整理。命中 1 條，另兩種手法依特性補（表內標明）。個別問題修了沒不在這頁講。

## 一、連線圖

```{.mermaid cap="C24 — 代理程式抓 url 型規則包。雲端建基準時先抓一次（C19：只收 https、擋內網 IP、限 50MB、算 sha256 落庫），派工時把 url 與 sha256 一起下發；代理程式拿到 url 原樣交給 cinc-auditor 自己去抓，sha256 沒用上。紅色：這一跳沒有完整性比對、不經 agent 自己的下載器。"}
%%{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
    ADMIN(["👤 客戶管理員<br/>填規則包網址"])
    subgraph MAIN["🏠 主系統"]
        API["guidant-api<br/>C19：抽取一次<br/>只收 https・擋內網・限 50MB<br/>算 sha256 落庫"]
    end
    URL(["🌐 規則包網址<br/>（客戶或第三方的伺服器）"])
    MITM(["🕵 路徑上的人<br/>或網址的主人"])
    subgraph AGENTBOX["🏢 客戶機房"]
        direction TB
        AG["evidence-agent<br/>收到 {url, sha256}"]
        CINC["cinc-auditor<br/>自己抓 url・載入即執行<br/>（不比 sha256）"]
        AG -- "url 原樣交出" --> CINC
    end
    HOSTS(["受檢主機（C23）"])
    ADMIN -- "C02" --> API
    API -. "C19 · https" .-> URL
    API -- "C20 · 派工帶 {url, sha256}" --> AG
    CINC == "C24 · https（舊基準可能 http）" ==> URL
    MITM -. "換內容" .-> CINC
    CINC -- "帶客戶帳密去跑規則" --> HOSTS
    classDef ext fill:#FBFCFC,stroke:#9AA8AA,stroke-dasharray:3 2
    classDef open fill:#FDECEC,stroke:#C0392B
    class ADMIN,URL,MITM,HOSTS ext
    class CINC open
```

## 二、這條線怎麼連

| 項目 | 現況 |
|---|---|
| **誰 → 誰** | 客戶機房的 `evidence-agent`（實際是它起的 `cinc-auditor` 子行程）→ 客戶管理員在「檢測基準」頁填的網址。那個網址可能是客戶自己的檔案伺服器、GitHub、或任何第三方 |
| **協定／埠** | HTTPS（新登記只收 `https://`——白名單直接取 `safe_http_fetch.ALLOWED_SCHEMES`，不另立一份；`http://` 回錯誤碼 `DETECTION_TOOLS_400013`）。**既有的 http 基準不強制失效**（避免客戶既有基準一次全滅），抽取時寫一筆醒目警告 |
| **傳什麼** | 規則包壓縮檔（InSpec profile：`inspec.yml`＋Ruby 檢查腳本）。cinc-auditor 下載、解壓、載入——**載入即執行**，規則包裡的 Ruby 想做什麼就做什麼 |
| **怎麼驗身分** | **無**。網址的伺服器不認 agent，agent 也不認伺服器（走 https 時由 cinc-auditor 的 HTTP 客戶端驗系統 CA；http 時全無） |
| **完整性比對** | **雲端有做、agent 沒接**。雲端第一次抽取成功時把下載到的壓縮檔 sha256 落庫（`detection_tool_profile_versions.sha256`），派工時 `build_payload()` 把 `{uid, source_type: "url", url, sha256}` 下發；**agent 端 `profile_cache.resolve_profile_source()` 對 url 型「原樣回傳 URL 字串，不經 cache、不比對」**——程式註解明寫「平台不經手檔案，交給 cinc-auditor 自己去取（現行為）」。所以雲端解析過的那份與 agent 實際跑的那份，**沒有任何機制保證是同一份** |
| **跟 file 型的差別** | file 型規則包經 [C20](C20-agent-to-frontdoor.html) 從雲端下載、sha256 對帳 `required=True`（缺指紋直接擋）、安全解壓到 cache；url 型全部跳過，由第三方工具直接抓 |
| **雲端那頭（C19）怎麼抓** | `safe_http_fetch.fetch_url_bytes`：只收 https、**解析後每一顆 IP 不得落私有／保留段**（擋 RFC1918、loopback、雲端 metadata）、限 50MB、自己走重導向最多 3 跳（每跳重驗 IP）。這些保護**只在雲端那一跳**，agent 這一跳沒有 |
| **何時存在** | 客戶用網址（不是上傳檔）建了檢測基準，且派 CINC Auditor／GCB 掃描時 |

依據：套件 `jedi_detection/app/service/detection_profile_service.py:959-962`（只收 https）、`jedi_detection/common/detection_profile_ref.py:43-73`（`build_payload` url 型帶 sha256）、`jedi_detection/common/safe_http_fetch.py`（C19 的四道保護）、`detection_profile_extraction_service.py:456-469`（抽取時算 sha256）；agent repo `core/profile_cache.py:124-144`（url 型原樣交出）、`core/task_executor_connectors/inspec.py:855-884`（`_resolve_profile` 交給 profile_cache 分流）。

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

| 群 | 功能 | 對威脅的意義 |
|---|---|---|
| **① 掃描時載入規則包** | 派 CINC Auditor／GCB 掃描、基準是 url 型 → 每台 agent 每次掃描都去抓一次 | 規則包決定「檢查什麼、怎麼判定合規」——換了規則包，掃描報告就是假的；規則包是 Ruby，換了規則包也能在 agent 容器裡跑任意程式（[C23b](C23b-agent-local-processes.html) T1） |
| **② 雲端抽取**（C19，不是本線） | 建基準或更新來源時，雲端抓一次解析控制項清單給畫面看 | 這一跳有完整保護；問題是它保護的那份內容，agent 不一定拿到同一份 |

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

掃描在這條線上抓到 1 條問題（[M03-5](../STRIDE/E-elevation-of-privilege.html#m03-5)）。依這條線的特性再補兩種手法（T2、T3 **無掃描實例**，風險欄標明）。

| # | 風險 | 威脅 | 駭客怎麼打 | 得手什麼 | STRIDE | 實例 |
|---|---|---|---|---|---|---|
| T1 | 🟡 中 | **在下載路徑上換掉規則包——不加密連線不用破解，加密連線也沒人比指紋** | ① 客戶管理員用一個網址建了檢測基準（舊基準可能是 http）；② 攻擊者站在代理程式下載的網路路徑上（同網段、DNS、代理伺服器）；③ 代理程式領到掃描工作，cinc-auditor 去抓規則包時，攻擊者回一包換過的；④ 規則包裡的 Ruby 在 agent 容器（root）執行——讀憑證、開後門；同時用客戶主機帳密登進受檢主機跑假檢查，報告也一起造假；⑤ 若是 http，連破解都不用；若是 https，雲端下發的 sha256 agent 沒比，換了也不知道 | 在客戶內網的代理程式上執行任意程式碼，並偽造掃描結果 | [T 竄改資料](../STRIDE/T-tampering.html)、[E 權限提升](../STRIDE/E-elevation-of-privilege.html) | [M03-5 網址型規則包放行不加密連線、也不記指紋](../STRIDE/E-elevation-of-privilege.html#m03-5) 🟡 |
| T2 | —（無掃描實例） | **網址的主人事後換內容——雲端看到的是 A、agent 跑的是 B** | ① 攻擊者控制那個網址（自己架的、或攻下了客戶的檔案伺服器、或 GitHub 帳號被盜）；② 建基準時放一份正常的規則包，讓雲端抽取、解析、算指紋、管理員在畫面上審過；③ 之後換成惡意版本；④ 每次派掃描 agent 都去抓最新的——拿到的是 B，但畫面上顯示的控制項清單還是 A 的；⑤ 不需要站在網路路徑上，不需要破解 TLS | 同 T1，但攻擊者不必在內網 | [T 竄改資料](../STRIDE/T-tampering.html)、[E 權限提升](../STRIDE/E-elevation-of-privilege.html) | — |
| T3 | —（無掃描實例） | **用規則包網址讓 agent 替人探內網、或抓巨檔撐爆** | ① 有權建檢測基準的人填 `https://10.0.0.5/x.tar.gz`——雲端那跳擋內網 IP，抽取會失敗；**但基準仍可建立**（抽取失敗只是沒有控制項清單），派工時 url 照樣下發；② agent 的 cinc-auditor 從客戶內網去抓——這一跳沒有內網限制、沒有大小上限；③ 連得上／連不上從掃描失敗訊息看得出；或指向一個數 GB 的檔讓 agent 磁碟吃光 | 客戶內網探測；agent 停擺 | [I 資料外洩](../STRIDE/I-information-disclosure.html)、[D 讓服務停擺](../STRIDE/D-denial-of-service.html) | — |

**三種手法的共同點**：全部來自**同一個結構性缺口——雲端審的那份與 agent 跑的那份是兩次獨立下載，中間沒有任何東西把它們釘在一起**。sha256 已經算了也下發了，agent 端沒用上；C19 的四道保護（https、擋內網、限大小、限重導向）只保護雲端那一跳。這條線的本質風險不是「網址不安全」，是「同一個網址抓兩次，信任只建立在第一次」。

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

對應三種威脅，防線分五條。D1、D2 直接對應掃描抓到的手法；**標 ◇ 的是依這條線的特性補的，沒有實例**。「目前」欄寫程式裡實際有的機制；⚠️ 表示沒有機制。

| # | 防線 | 擋哪種威脅 | 目前做到哪 |
|---|---|---|---|
| D1 | **只收加密連線**：新登記 https 限定；既有 http 基準要有退場（警告→期限→停用） | T1 的「不用破解」那半 | ✅ 新登記只收 https，白名單取自 `safe_http_fetch.ALLOWED_SCHEMES` 不另立；✅ 既有 http 抽取時寫醒目警告。⚠️ 既有 http 基準**不強制失效、沒有退場期限**——裁定避免客戶既有基準一次全滅，但也等於 http 這條路永遠開著 |
| D2 | **agent 端比對雲端下發的指紋**：url 型也走 agent 自己的下載器（而非交給 cinc-auditor）→ sha256 對帳 → 安全解壓 → 餵目錄給引擎，與 file 型同一條路 | T1 的「沒人比指紋」那半、**T2 全部** | ⚠️ **沒有**。雲端 `build_payload()` 已下發 sha256；agent `profile_cache.resolve_profile_source()` 對 url 型原樣回傳不比對。M03-5 的狀態欄明寫「代理端比對指紋屬後續小卡，本次未見對應 commit」——**這就是那張小卡要做的事**，兩頭差一步 |
| D3 ◇ | **內容漂移要可見**：雲端定期（或每次派工前）重抓算 sha256，與落庫值不符就警告管理員「網址內容已變更，請重新審核」；派工時若不符則拒派 | T2 | ⚠️ **沒有**。抽取是一次性的（建基準或手動重新解析）；之後網址內容變了雲端不知道、畫面上的控制項清單是舊快照（程式註解明寫「url 型的清單是外部網址某一刻的快照，內容會漂」） |
| D4 ◇ | **agent 這一跳也要有 C19 那四道**：擋內網 IP、限大小、限重導向、逾時——不信雲端一定擋過 | T3 | ⚠️ **沒有**。cinc-auditor 自己抓，agent 管不到它的下載行為。做了 D2（改走 agent 下載器）這條就順帶有了——agent 的 `_get_stream` 已有大小上限與取消檢查，再加 IP 檢查即可 |
| D5 ◇ | **url 型基準要過審才能派**：抽取失敗（網址抓不到、不是合法規則包）的版本不得進入可派工狀態 | T3 的「抽取失敗仍可建」那一步 | ⚠️ 抽取失敗只影響控制項清單顯示，**基準本身仍可建立並派工**（`build_payload` 對 url 型只要 `profile.url` 有值就下發；`sha256` 可為 `None`，註解寫「屬已知缺口而非錯誤」）。沒查到「抽取成功才可發布」的狀態機約束 |

**最該補的一步**：D2，而且它已經在排程裡（M03-5 的後續小卡）。做法就是把 url 型從「原樣交出」改成「走 file 型同一條路」：agent 自己下載（順帶拿到 D4 的大小與 IP 限制）→ 比對下發的 sha256（T1、T2 一起擋掉）→ 解壓進 cache → 餵目錄給 cinc-auditor。`profile_cache.py` 的 file 型流程全部現成，差的是 url 型那個 `return url` 的分支改接過去。

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

- **agent 端 url 型處理**（D2、D4）：掃描的 M03-5 是雲端套件那頭的條目，agent 端「原樣交出」這段沒有條目——它是 M03-5 打折的那一半。
- **內容漂移偵測**（D3）：雲端完全沒有重抓機制，六頁零條。
- **url 型基準的狀態機**（D5）：抽取失敗能不能派，沒查到約束。
- **cinc-auditor 自己的下載行為**：它用什麼 HTTP 客戶端、驗不驗憑證、有沒有大小上限——這是 Ruby 工具內部，沒查。做了 D2 這題就消失。
- **http 基準的退場**（D1）：有多少既有基準還是 http，沒查 DB。

---

*依據：STRIDE 六頁信任邊界連線標記（CM-2403／2404 驗收後版本）、套件 `jedi_detection/app/service/detection_profile_service.py`／`detection_profile_extraction_service.py`／`common/detection_profile_ref.py`／`common/safe_http_fetch.py`、agent repo `core/profile_cache.py`／`core/task_executor_connectors/inspec.py`／`core/task_executor.py`、DFD Level 0 §2.3（C19）／§2.4（C24）。*
