Guidant AI 資安檢視總報告 · 連線清單

C21 主系統 api → 代理程式資料面(HTTPS :8443,mTLS)

唯一一條由我們雲端主動連進客戶機房的線。「測試連線」按鈕、取消掃描、取回證據檔都走它,而且請求裡會帶解密後的工具帳密要代理程式拿去連內網。這一頁回答:這條線怎麼連、哪些功能走它、它帶來什麼威脅、駭客怎麼打、我們要怎麼防、目前做到哪。

裝了 agent 才有 客戶要開 8443 入站 威脅 4 種 掃描命中 4 條

這一頁怎麼來的:DFD Level 0 把產品運作時的連線編成 C01~C25;STRIDE 六頁每一條問題都標了發生在哪幾條線。這裡以連線為單位整理。個別問題修了沒不在這頁講,請點條目連回 STRIDE 頁。

§1

一、連線圖

%%{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/>按「測試連線」"])
    subgraph MAIN["🏠 主系統 stack"]
        API["guidant-api<br/>解密工具帳密<br/>簽 60 秒 JWT<br/>出示雲端客戶端憑證"]
    end
    subgraph AGENTBOX["🏢 客戶機房"]
        direction TB
        subgraph AG["evidence-agent :8443(agent 自起 TLS)"]
            direction TB
            MTLS["① 要求客戶端憑證<br/>(CERT_REQUIRED)"]
            JWTG["② 驗 JWT:簽章・發行者・<br/>aud=本機編號・bound_fp=本機指紋・60 秒"]
            EP["/detection/probe 測試連線<br/>/detection/cancel 取消<br/>/blob/… 取檔"]
            OPEN["/health・/agent-info<br/>不驗"]
            MTLS --> JWTG --> EP
            MTLS --> OPEN
        end
        TOOL(["🖥 內網:受檢主機/工具伺服器"])
        EP -- "C23/C23a · 用請求帶的帳密去連" --> TOOL
    end
    U -- "C02" --> API
    API == "C21 · HTTPS :8443 · mTLS+JWT<br/>body 含明文工具帳密" ==> MTLS
    classDef ext fill:#FBFCFC,stroke:#9AA8AA,stroke-dasharray:3 2
    classDef open fill:#FDECEC,stroke:#C0392B
    class U,TOOL ext
    class OPEN open
C21 — 雲端打進代理程式 :8443。這是反方向的線:客戶防火牆要放行入站 8443。agent 自己起 TLS 伺服器並強制要雲端出示客戶端憑證(真 mTLS),再驗一張 60 秒短效 JWT——綁這台的編號與硬體指紋。/health 與 /agent-info 兩支不驗。
§2

二、這條線怎麼連

項目 現況
誰 → 誰 我們的 guidant-api → 客戶機房 evidence-agent 容器的 :8443。方向是雲端連入客戶,客戶防火牆要放行 8443 入站;agent 的對外位址在安裝時填(AGENT_BASE_URL),報到時回報給雲端存在 remote_agents.base_url
協定/埠 HTTPS :8443。TLS 由 agent 程式自己承接(nginx sidecar 已退役),最低 TLS 1.2。認證模式下雲端要求 base_url 必須是 https://,否則不發
傳什麼 三件事:① 測試連線(POST /detection/probe)——body 帶解密後的工具帳密(SSH/WinRM 密碼、OpenVAS/ZAP/SonarQube 帳密或權杖)與目標主機清單,要 agent 就近去連並回成敗;② 取消掃描(POST /detection/cancel)——帶任務編號;③ 取檔(GET /blob/<uid>、/blob/<uid>/sha256、/blob/<uid>/pdf)——雲端從 agent 暫存取回證據檔
怎麼驗身分 兩層,真 mTLS:① agent 的 TLS 伺服器設 verify_mode = CERT_REQUIRED,雲端必須出示由同一個內部 CA 簽的客戶端憑證(BE .env 的 AGENT_CLOUD_CLIENT_CERT/KEY),沒帶直接 400;② 通過 TLS 後,before_request 驗 Authorization: Bearer <JWT>——RS256 簽章、發行者固定、受眾必須等於這台 agent 的編號、bound_fp 必須等於這台的硬體指紋(product_uuid+machine-id 算出)、效期 60 秒(AGENT_JWT_TTL_SEC,每次請求現簽)
哪些不驗 /health(容器健康檢查用、綁 :8000 僅容器內)與 /agent-info 不在受保護前綴內,:8443 上也打得到。/agent-info 回什麼要注意(見六)
雲端怎麼信 agent 雲端用內部 CA(AGENT_CA_CERT)驗 agent 出示的伺服器憑證——那張是 agent 報到時雲端自己簽的,SAN 取安裝時填的對外位址
帳密在這條線上的樣子 probe 的 body 是明文帳密(TLS 保護傳輸)。agent 端只在本次請求記憶體內使用、不落地、log 只記主機與工具不記帳密
何時存在 客戶有裝代理程式、且雲端 AGENT_AUTH_MODE=full(installer 預設寫 full)。mode=none 是 demo 模式:裸 http、不驗任何東西——正式部署不該出現

依據:agent repo core/data_plane_server.py(CERT_REQUIRED)、core/data_plane_auth.py(受保護前綴 /blob、/detection;JWT 四項檢查)、core/agent_auth.py(verify_data_plane_jwt)、api/detection/routes/detection_route.py、api/blob/__init__.py;套件 jedi_remote_agent/common/agent_auth/tls.py(雲端 mTLS context)、jwt_util.py(jwt_ttl_sec=60)、jedi_detection/infra/detection_tools/connector/agent_probe_client.py;主專案 config/config.py:274-284、scripts/installer/install.sh:1705(AGENT_AUTH_MODE=full)。

§3

三、哪些功能會走這條線

群 功能 對威脅的意義
① 測試連線 檢測工具設定頁的「測試連線」按鈕:雲端把該租戶的工具帳密解密、連同目標主機清單送給 agent,agent 用既有 connector 去連並回「成功/失敗+訊息」 這是唯一一條會把解密後的客戶帳密主動送出雲端的路徑(掃描本身是 agent 來領、見 C20)。誰能按、按下去連到哪、結果回什麼,三件事都是攻擊面
② 取消掃描 使用者按取消,雲端通知 agent 真的中斷正在跑的子行程 影響的是可用性與紀錄完整性,不帶祕密
③ 取回證據檔 掃描報告先存在 agent 旁的 SeaweedFS(C22),雲端經這條線取回寫進主系統儲存 取回的檔案會進證據清單、被人預覽——內容可信度在 C20 T2 討論
§4

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

掃描在這條線上抓到 4 條問題(M01-1、M03-2、M03-14、M03-6),歸納起來是四種攻擊手法。這條線特別的地方:它的入口在雲端那頭的畫面——三條(T2~T4)都是先在畫面上按一顆按鈕,雲端替攻擊者把帳密與請求送進客戶內網。

# 風險 威脅 駭客怎麼打 得手什麼 STRIDE 實例
T1 🔴 最嚴重 冒充雲端打進客戶機房 ① 連得到客戶的 :8443(同一內網、或客戶把 8443 開到了公網);② 若 agent 不要求客戶端憑證、或不驗 JWT 的受眾與指紋,就能照格式送一個 /detection/probe,帶自己編的「帳密」與目標——讓 agent 替他去敲內網任何主機;③ 或送 /blob/<uid> 把 agent 暫存的證據檔取走 把客戶內網的代理程式當跳板掃內網;取走掃描報告 S 冒充身分、I 資料外洩 M01-1 代理程式五條通訊管道全部不檢查對方是誰 🔴(該條的「下載證據檔」通道在這條線上)
T2 🟠 高 誰都能按「測試連線」——按下去雲端就把帳密解密送出 ① 公司裡任何能登入的帳號(不需管理權限);② 打開檢測工具設定頁記下某份設定的編號;③ 直接送測試連線請求,端點若只驗登入不驗「你能不能改這份設定」,就把 SSH/WinRM 密碼與三套工具權杖解密、經這條線送到 agent;④ 目標主機若由請求指定(T3),帳密就送進攻擊者控制的機器 整家公司用來掃描主機的維運帳密與工具權杖 E 權限提升、I 資料外洩 M03-2 「測試連線」沒檢查權限,按下去就把維運帳密解密送到指定主機 🟠
T3 🟡 中 測試連線連到哪,由按的人自己填——代理程式變成內網探測器 ① 有權按測試連線的人;② 目標清單放一整段內網位址;③ agent 逐台去連;④ 從每台「連得上/被拒/逾時」的差異畫出客戶內網哪些機器開著哪些服務。帳密也隨之送到每一台 客戶內網的主機存活與服務分布圖;帳密被送到非預期主機 I 資料外洩 M03-6 「測試連線」要連到哪台主機由呼叫者自己指定 🟡
T4 🟡 中 不該動手的人取消或干擾正在跑的掃描 ① 以唯讀角色登入;② 對別人的掃描按取消,雲端經這條線叫 agent 真的中斷子行程;③ 反覆取消再重派,正常檢測永遠跑不完 干擾稽核檢測、改掉執行紀錄 E 權限提升、D 讓服務停擺 M03-14 唯讀角色可以對客戶機器發動掃描、刪掉執行紀錄 🟡(取消那一支走這條線)

四種手法的共同點:T1 是這條線自己的門——客戶機房對外開了一個埠,認錯對方就等於內網被接管。T2~T4 的門其實在 C02——這條線只是忠實地把雲端叫它做的事做掉;但因為它做的事是「拿客戶的鑰匙去開客戶的門」,上游守門一鬆,後果直接落在客戶內網。

§5

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

對應四種威脅與這條線的本質,防線分七條。D1~D4 直接對應掃描抓到的四種手法;標 ◇ 的(D5~D7)是依這條線的特性補的標準防線,掃描範圍沒涵蓋、沒有實例。「目前」欄寫程式與部署裡實際有的機制;⚠️ 表示目前只靠慣例或只守到局部。

# 防線 擋哪種威脅 目前做到哪
D1 入站兩層驗:先要憑證、再驗綁定這台的短效票。TLS 層強制客戶端憑證;JWT 要綁受眾(這台編號)與硬體指紋、效期以秒計、每次現簽 T1 ✅ build_server_ssl_context 設 CERT_REQUIRED(docstring 特別標紅:預設 CERT_NONE 會讓 CA 載入看似成功但完全不要求憑證);✅ JWT 驗簽章+iss+aud=agent_uid+bound_fp=device_uuid+exp,60 秒;✅ 每次請求讀當下的註冊狀態(重註冊換 uid 後立刻用新 uid 驗)。⚠️ /health、/agent-info 在 :8443 上不驗
D2 會送帳密出去的按鈕,要先問「你能不能改這份設定」。測試連線掛與新增/修改/重置相同的能力點守門 T2 ✅ 路由補上 @capability_required(plugin_update_capability),寫法照同檔三處既有宣告。⚠️ 這是唯一的防線——「連到哪裡」刻意不設白名單(D3)
D3 目標由呼叫者填,就要限量、收斂回應、記下誰按的:單次主機數上限;回應只回成功/失敗,逐台診斷進日誌;稽核日誌記操作者、客戶、設定、工具、代理程式、目標清單 T3 ✅ 三件都做了:DETECTION_TEST_CONNECTION_MAX_HOSTS 預設 32、回應收斂、稽核日誌。裁定不設目標白名單(掃描目標是客戶自己的主機,哪台算合法由客戶管)。⚠️ 所以「有權按的人把帳密送到自己機器」這條路依設計是開的——防線是 D2 的權限門,不是目標限制
D4 取消與重派只放行任務被指派人與專案管理者 T4 ✅ 八支寫入端點換成 assert_job_operator(見 C02 D1)
D5 ◇ agent 端對 probe 請求也要有上限:單次主機數、逾時、併發數——雲端的限制是一道,agent 自己再守一道,不信雲端一定對 T3 的延伸、T1 ⚠️ agent 端 DetectionProbeRoute 沒有自己的主機數上限,照雲端送來的清單逐台連;逾時由各 connector 自訂(OpenVAS 60 秒等)。雲端那層守住就沒事,但這條線的設計哲學是「不信對方」,agent 端應該也量一次
D6 ◇ 8443 只對雲端開:客戶防火牆只放行雲端的來源 IP;安裝文件要明寫 T1 ⚠️ 安裝手冊寫「雲端連得到本機 :8443(防火牆要放行 8443)」,沒說只放行雲端來源。mTLS 擋得住冒充,但開到公網就是多一個可被探測、可被打 TLS 層漏洞的埠
D7 ◇ demo 模式不得出現在正式部署:AGENT_AUTH_MODE=none 是裸 http、不驗任何東西 T1 ✅ installer 寫 AGENT_AUTH_MODE=full、agent compose 預設 full、雲端在 full 模式下拒絕非 https 的 base_url;維運工具 guidantai 在 mode 不對時明確報錯指路。⚠️ 主專案 config.py 預設值仍是 none——靠 installer 寫 .env 蓋掉;手動部署忘了設就是 demo 模式,且沒有啟動期檢查擋它

最該補的一步:D7 的預設值。AGENT_AUTH_MODE 在程式裡預設 none、靠 installer 寫成 full;正式設定類(StagingPremiseConfig 等)應該在啟動時檢查 mode != full 就拒絕啟動——同 SANDBOX_MODE 留空在正式設定會拒絕啟動的做法。一行檢查,擋掉「手動部署忘了設、整條線變裸 http」。

§6

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

  • /agent-info 在 :8443 回了什麼(D1):不驗身分就能打,回應裡若有版本、指紋、編號,等於幫攻擊者對 T1 做前置偵察。沒看。
  • agent 端的 probe 限量(D5):雲端限 32 台,agent 端沒再量;雲端被繞過時 agent 是最後一道。
  • 8443 暴露面(D6):客戶實際怎麼開防火牆沒人管得到,但安裝文件可以寫清楚。
  • AGENT_AUTH_MODE 的啟動期檢查(D7):正式設定類沒擋 none。

依據:STRIDE 六頁信任邊界連線標記(CM-2403/2404 驗收後版本)、agent repo core/data_plane_server.py/core/data_plane_auth.py/core/agent_auth.py/api/detection/routes/detection_route.py/api/blob/__init__.py/deploy/README.md/deploy/docker-compose.yml、套件 jedi_remote_agent/common/agent_auth/tls.py/jwt_util.py/settings.py、jedi_detection/infra/detection_tools/connector/agent_probe_client.py、主專案 config/config.py/scripts/installer/install.sh/scripts/installer/guidantai、DFD Level 0。