Guidant AI 資安檢視總報告 · 安全需求(SR)
每個入口都有上限
任何接受外部輸入的入口,都要有大小、速率、逾時、並行數的上限,失敗時不拖垮其他功能。這一章 9 條:前門、外部 AI、外部呼叫、背景工作、即時連線、資料庫、agent 暫存、掃描、Redis 與檔案儲存。4 條有掃描實例、5 條是標準做法。
「讓服務停擺」不需要攻破任何東西——一個特製請求、幾個分頁、一份壓縮炸彈就夠。系統有三種容易被拖垮的地方:共用的處理程序(前門、聊天框、背景 worker 一起吃同一台機器)、共用的資料層(整張表一次撈出來、交易開著一列列讀)、客戶機房裡的 agent(磁碟、記憶體小,停擺就是該客戶所有檢測停擺)。本章每條都是「某個入口少了某道上限」。
| # | 要求 | 來源 |
|---|---|---|
| SR-07.1 | 前門有請求大小與速率上限,免登入端點另有濫用上限與告警 | 標準做法 |
| SR-07.2 | 外部 AI 呼叫有長度、逾時、次數、額度四道上限 | 掃描驗證 |
| SR-07.3 | 所有外部呼叫有逾時,失敗不拖垮本地操作 | 標準做法 |
| SR-07.4 | 背景工作有去重、並行與深度上限,佇列有租約與重撿 | 掃描驗證 |
| SR-07.5 | 即時連線有同時連線數與事件速率上限,跨來源白名單與 HTTP 對齊 | 標準做法 |
| SR-07.6 | 資料庫做的事有上限 | 掃描驗證 |
| SR-07.7 | agent 側暫存有容量上限與清理,磁碟低水位告警 | 標準做法 |
| SR-07.8 | 掃描可即時取消、有逾時,預設強度保守 | 標準做法 |
| SR-07.9 | Redis 不持久化、不留免密入口,衍生檔同生共死 | 掃描驗證 |
| 欄位 | 內容 |
|---|---|
| 要求 | 前門必須對所有請求設大小上限與每來源速率上限,不得以「交後端各自把關」代替;不需登入的端點(OAuth 回呼、Drive webhook、忘記密碼、驗證碼)必須另有濫用上限:失敗次數有速率限制並告警,不讓人拿這類端點對 Redis 或日誌灌流量 |
| 為什麼 | 前門不擋時,單一來源用大量或大體積請求就能耗盡後端;免登入端點任何人可無限次打,Redis 查詢與日誌會被灌滿,真正的異常訊號被淹沒 |
| 適用連線 | C01 瀏覽器 → 前門、C04 瀏覽器 → api(Drive OAuth 回呼)、C14 api → Google Drive;推及:C02 前門 → api(前門到 api 的所有端點共用前門上限) |
| 對應威脅 | C01 T2 驗身分之前的處理被餵特製內容,把全站卡死 🟠、C14 T5 從不需登入的通知入口與驗憑證按鈕下手 ⚪ |
| 驗證方式 | 對任一端點送超過上限的內容,前門必須回 413 且請求不到後端;單一來源在一分鐘內對回呼與 webhook 端點連送超過上限次數,之後的請求必須被限速並產生一筆告警 |
| 來源 | 標準做法:C01 D7◇、C04 D4◇、C14 D7◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 呼叫外部 AI 之前必須有四道上限:訊息長度(在路由最外層擋,不等進服務才量)、呼叫逾時(外部回得慢時系統自己放棄)、每人每分鐘次數(跨行程累計,不得各行程各算各的)、每租戶與每人每日美元額度;任一道超限必須回明確錯誤 |
| 為什麼 | 聊天框是任何登入員工都能開的入口:開四到八個分頁各送一則超大訊息,處理程序被全部佔住,其他人連登入畫面都打不開;或把公司共用的 AI 額度燒光變成帳單 |
| 適用連線 | C13 api → 外部 AI |
| 對應威脅 | C13 T3 用聊天框把處理程序佔光、把額度燒光 🟡 |
| 驗證方式 | 單一帳號同時開 8 個分頁各送超長訊息,其他帳號登入與其他頁面必須仍正常回應;一分鐘內超過次數上限必須被拒;模擬外部 AI 不回應,請求必須在逾時內失敗而非無限等待;累計用量超過每日額度後必須被拒 |
| 來源 | 掃描驗證:C13 D3(實例 M14-1) |
| 欄位 | 內容 |
|---|---|
| 要求 | 系統對外部服務(AI、GitLab/GitHub、Discord、Telegram、授權簽發站、Google Drive、SMTP)的每一次呼叫必須設逾時;外部失敗或過慢不得使本地操作失敗或變慢(背景發送要有逾時,不得讓執行緒永遠掛著;清單頁不得因外部慢而慢);失敗必須有紀錄 |
| 為什麼 | 沒設逾時的外部呼叫會讓處理程序或執行緒永遠掛著,外部服務一掛,本地功能跟著累積卡死直到整個服務停擺 |
| 適用連線 | C15 api → 問題追蹤(GitLab/GitHub)、C16 api → 聊天 webhook(Discord/Telegram);推及:C10 api → 客戶 SMTP(寄信)、C12 api → 客戶 SIEM(日誌轉送)、C13 api → 外部 AI(AI)、C14 api → Google Drive(Google Drive)、C18 api → 授權簽發站(授權簽發站) |
| 對應威脅 | 無掃描實例(標準做法) |
| 驗證方式 | 把各外部位址換成一個接受連線但不回應的測試伺服器,各功能必須在設定的逾時內返回錯誤;同時開清單頁,頁面回應時間不得隨外部延遲增加(有外部資料的清單可降級顯示) |
| 來源 | 標準做法:C15 D5◇、C16 D4◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 背景工作入列必須有去重(同一資源同類工作不重複排)、並行上限、排隊深度上限;每條工作必須有資源上限(記憶體、處理時間、外部程序數);佇列必須有租約與心跳、死掉的 worker 的單必須被重撿、重試必須有上限、停機時必須做完手上的單;多 worker 不得搶同一張單 |
| 為什麼 | 有權限的帳號對同一資源連打幾百次「重新解析」,每次開一條吃 50MB 記憶體與最長 15 分鐘外部程式的背景工作,同一台機器上所有客戶一起變慢;單卡死而沒有租約,就永遠占著位置 |
| 適用連線 | C09 api → worker(背景工作);推及:C19 api → 規則包網址(規則包解析工作)、C08 worker → 沙箱(拆檔)(拆檔工作) |
| 對應威脅 | C09 T3 入列沒有上限、沒有去重,用背景工作把主機打掛 🟡 |
| 驗證方式 | 對同一版規則包連送 100 次重新解析,佇列中該類工作不得超過去重後的上限,且並行數不得超過設定值;殺掉持單中的 worker,單必須在租約逾時後被另一 worker 撿起;單連續失敗必須在重試上限後標為失敗,不再重排 |
| 來源 | 掃描驗證:C09 D4(實例 M03-10、M07-8、M24-15);標準做法:C09 D7◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 即時連線(socket)必須限制每個使用者同時連線數與每秒事件數;跨來源白名單必須與 HTTP 側一致,只接受本站來源,不得預設放行所有來源 |
| 為什麼 | 長連線加上「每個事件寫一次資料庫」的設計,單一帳號開大量連線或高頻 update 就能占滿 socketio 行程與資料庫寫入;來源不限時,任何網站的頁面都能對已登入使用者發起連線 |
| 適用連線 | C03 前門 → socketio |
| 對應威脅 | 無掃描實例(標準做法) |
| 驗證方式 | 同一帳號建立超過上限數的連線,超出的必須被拒;單一連線一秒內送超過上限的 update 事件,超出的必須被丟棄或限速;從不在白名單內的 Origin 發起交握必須被拒 |
| 來源 | 標準做法:C03 D6◇、C03 D5◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 資料庫查詢與匯入必須有上限:每頁筆數在共用分頁格式設上限(超過即截到上限);連線設 statement_timeout;讀檔解析必須用串流、連續空白視為檔尾、列數有上限;寫入端必須拒絕空內容;讀取端遇一筆壞資料不得使整份查詢失敗 |
| 為什麼 | 任何登入帳號把「一頁幾筆」改成超大數字就能讓資料庫整張表撈出;幾 KB 的稽核表在第 20 萬列填一格,匯入就從頭讀到那裡且整段交易一直開著;一筆空白範本讓所有人打開清單頁都 500 |
| 適用連線 | C05 api → 資料庫;推及:C02 前門 → api(所有分頁清單與匯入端點) |
| 對應威脅 | C05 T6 一個請求讓資料庫做太多:整張表撈出來、交易開著一列列讀**(4 條) 🟡 |
| 驗證方式 | 對任一清單端點送 page_size 超大值,回傳筆數必須被截到上限;匯入一份在極遠列有內容的小檔,必須在列數上限處中止、交易不得長時間開著;存一筆空內容範本必須被拒;人為在表中放一筆格式損壞的資料,清單頁其餘資料必須仍能顯示 |
| 來源 | 掃描驗證:C05 D6(實例 M04-7、M12-3、M06-8、M19-3) |
| 欄位 | 內容 |
|---|---|
| 要求 | agent 的物件儲存 bucket、工作目錄與 cache 必須有容量上限與清理機制(已被雲端取回的檔定期清);可用磁碟低於門檻必須告警;agent 對收到的 probe 請求必須自己再守一道上限(單次主機數、逾時、併發數),不得只信雲端的限制 |
| 為什麼 | 客戶機房的 agent 磁碟小,沒有容量上限時等著就會滿,agent 寫不進報告、掃描全部失敗,雲端只看到「上傳失敗」;雲端的限制只是一道,雲端出錯或被冒充時 agent 自己沒有第二道 |
| 適用連線 | C22 agent → SeaweedFS、C23b agent 本機程序、C21 api → agent 資料面(:8443) |
| 對應威脅 | C22 T3 塞爆磁碟讓 agent 停擺(無掃描實例)、C23b T3 特製壓縮包或巨型 repo 把 agent 主機撐爆(無掃描實例)、C21 T3 測試連線連到哪,由按的人自己填——代理程式變成內網探測器 🟡、C21 T1 冒充雲端打進客戶機房 🔴 |
| 驗證方式 | 把 bucket 寫到配額上限,之後的寫入必須被拒並產生告警;把磁碟剩餘壓到門檻以下必須觸發告警;對 agent 資料面送超過單次主機數上限的 probe,必須在 agent 端被拒 |
| 來源 | 標準做法:C22 D4◇、C23b D6◇、C21 D5◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 每一次掃描必須可即時取消並有逾時;預設強度必須保守:Nmap 預設 connect 掃描、不得預設 SYN 全埠;OpenVAS 不得預設會打掛設備的 config;ZAP active scan 必須由使用者明確勾選才開 |
| 為什麼 | 掃描流量對老舊印表機、網路設備、工控系統就是攻擊,預設太重會直接打掛客戶內網設備,而且是「我們的產品」造成的;停不掉的掃描讓傷害持續擴大 |
| 適用連線 | C25 掃描引擎 → 目標 |
| 對應威脅 | C25 T2 掃描流量打掛內網脆弱設備(無掃描實例)、C25 T3 掃描流量觸發客戶自己的防禦,agent 被封(無掃描實例) |
| 驗證方式 | 新建一個未調整任何選項的任務,檢查實際下發的引擎參數:Nmap 不得為 SYN 全埠、OpenVAS 不得為會打掛設備的 config、ZAP 不得啟用 active scan;掃描進行中按取消,目標端的探測流量必須在數秒內停止;任務超過逾時必須被中止 |
| 來源 | 標準做法:C25 D5◇、C25 D3◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | Redis 必須不對外、不持久化、不留免密入口;檔案的衍生檔(預覽轉出的 PDF)必須在主檔刪除時一併清除,物件儲存與本機儲存走同一套;切換儲存後端時不得丟舊檔——每個檔必須記錄自己躺在哪種後端、讀取時借對應設定 |
| 為什麼 | Redis 持久化或免密時,暫存內容(AI 對話、共編名單)落到磁碟或被同網段的人直接讀寫;衍生檔不跟著刪,使用者以為已刪除的敏感內容仍留在硬碟;切換後端丟舊檔則證據遺失 |
| 適用連線 | C06 api → Redis、C07 api → 檔案儲存 |
| 對應威脅 | C07 T5 刪了主檔,預覽時轉出的 PDF 還留在儲存裡 ⚪ |
| 驗證方式 | 從主機外對 Redis 埠連線必須被拒;不帶密碼連 Redis 必須被拒;確認 Redis 設定無持久化且重啟後無舊資料;上傳並預覽一份檔後刪除,儲存中該檔的主檔與轉出的 PDF 必須都不存在;切換儲存後端後,切換前上傳的檔必須仍可下載 |
| 來源 | 掃描驗證:C07 D5(實例 M02-9);標準做法:C06 D2◇、C07 D8◇ |
來源:連線頁的防線(D);去重對照在 requirements/_drafts/D-to-SR.md。