Guidant AI 資安檢視總報告 · 安全需求(SR)
出口跳脫、回應白名單、安全標頭、推出去的最小化
資料從我們這裡「出去」的每一個口——匯出檔、信件、日誌轉送、HTTP 回應、第三方頻道、外部 AI——都要在出口處理:內容依目的地格式跳脫、回應只給該給的欄位、瀏覽器端有兜底標頭、推出去的只說「有事發生」。這一章 5 條:2 條有掃描實例、3 條是標準做法。
輸入章(SR-04)管「進來的東西不能信」,這一章管「出去的東西要處理」。同一段使用者填的文字,放進 Excel 是公式、放進 Word 範本是語法、放進 HTML 信件是網頁、放進目錄查詢是篩選條件、放進日誌是換行——每個目的地的「特殊字元」不一樣,所以跳脫必須在出口、依目的地做,不能在入口做一次了事。回應與標頭是另一側:瀏覽器收到什麼、第三方頻道收到什麼、外部 AI 收到什麼,都應該是「有清單可說明的最小集合」。
| # | 要求 | 來源 |
|---|---|---|
| SR-05.1 | 使用者輸入在出口依目的地格式跳脫 | 掃描驗證 |
| SR-05.2 | 回應欄位白名單;設定類回應遮密鑰;錯誤只回代碼 | 掃描驗證 |
| SR-05.3 | 前門對所有回應加安全標頭 | 標準做法 |
| SR-05.4 | 推到第三方頻道的內容最小化 | 標準做法 |
| SR-05.5 | 資料出境(外部 AI)的範圍有清單、客戶看得到 | 標準做法 |
| 欄位 | 內容 |
|---|---|
| 要求 | 任何使用者填的文字,在離開系統的出口必須依目的地格式跳脫,不在入口一次處理:Excel 匯出——以 =、+、-、@ 開頭的儲存格前加 ';Word 範本——範本語法({{…}})轉義;HTML 信件——放進範本前一律 html.escape();LDAP 查詢——*、括號、反斜線等篩選條件特殊字元不得原樣進 filter;Google 搜尋語法——先把反斜線換成兩個、再跳脫單引號(順序不能反),資料夾編號驗格式;Markdown 訊息(Telegram)——跳脫 Markdown 特殊字元,Discord 至少去掉 @everyone/@here 與連結語法;日誌轉送(syslog)——換行、歸位、定位、反斜線轉成看得見的轉義字元,在格式化器(出口)做,不在記錄點做。內容一個位元都不得少,只改呈現形式 |
| 為什麼 | 欄位裡的一段字在別人電腦、我們的伺服器或客戶的監控系統裡被當成指令執行:稽核人員開 Excel 時執行公式、系統以官方寄件身分發出釣魚信、帳號欄塞萬用字元以任一員工身分登入、往客戶的資安監控系統捏造稽核紀錄 |
| 適用連線 | C02 前門 → api(匯出 Excel/Word)、C10 api → SMTP(HTML 信件)、C11 api → LDAP(查詢字串)、C14 api → Google Drive(搜尋語法)、C16 api → 聊天 webhook(Markdown 訊息)、C12 api → SIEM(日誌控制字元) |
| 對應威脅 | C02 T9 使用者的字變成程式:公式、範本語法、網頁、AI 指令 🟠、C10 T4 用系統的寄件身分發釣魚信 ⚪、C11 T2 帳號欄塞萬用字元改寫查詢 🟠(無掃描實例)、C14 T4 使用者的字拼進 Google 的搜尋語法 🟡、C12 T2 往客戶的 SIEM 塞假紀錄 🟡、C16 T2 用系統的名義在客戶頻道發釣魚訊息(無掃描實例,同 C10 T4 的 M06-27) |
| 驗證方式 | 逐目的地各打一筆:暱稱填 =cmd|' /C calc'!A0 後匯出任務 Excel,儲存格內容必須以 ' 開頭、不得被 Excel 當公式;描述填 {{ 1+1 }} 後匯出 Word,文件內必須原樣顯示;暱稱填 <a href=…>請重新登入</a> 後觸發通知信,信件原始碼必須是 <a…;LDAP 登入帳號填 *,必須登入失敗;專案名稱結尾帶 \ 加 ' 後重建雲端資料夾,搜尋條件不得被改寫;登入帳號欄填「名字+換行+假日誌」,SIEM 收到的必須是一筆含 \n 字樣的紀錄;Telegram 暱稱填 [請重新登入](https://x),頻道裡必須看到原始字元而非連結 |
| 來源 | 掃描驗證:C02 D7(實例 M21-1、M11-18、M11-19、M11-20、M06-26)、C10 D4(實例 M06-27)、C11 D2、C14 D4(實例 M07-4、M24-14)、C12 D2(實例 M09-4)、C16 D2◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 回應 schema 必須採白名單:只回明列的欄位,不得「資料上有什麼就吐什麼」。設定類回應(儲存空間、郵件、AI 金鑰、整合憑證)密鑰欄位一律遮蓋,遮蓋依「欄位標記」而非人工維護的名單,新欄位預設視為機密、明確標為非機密才放行。錯誤訊息只回錯誤代碼,資料庫原始錯誤、解析器例外、伺服器暫存路徑只進日誌。失敗紀錄只記位址與錯誤類別,帶密碼的設定物件不得進任何日誌 |
| 為什麼 | 任何登入帳號打一支「查設定」端點就拿到儲存空間與郵件伺服器的帳號密碼明文;錯誤訊息把資料庫原始錯誤、內部路徑整段回給畫面;寄信失敗把整組設定連密碼寫進紀錄,看得到紀錄或診斷包的人搜尋就得到憑證 |
| 適用連線 | C02 前門 → api(所有設定與錯誤回應)、C10 api → SMTP(失敗紀錄不帶密碼);推及 C15、C16(兩者都有「憑證讀取遮罩」的對應防線,同一要求) |
| 對應威脅 | C02 T8 回應帶太多:設定連密碼一起回、錯誤訊息吐內部細節 🟠、C10 T3 寄信失敗把密碼寫進紀錄 🟡 |
| 驗證方式 | 以一般登入帳號(非管理員)打每一支設定讀取端點,回應中所有密鑰欄位必須為遮罩值、整份回應搜尋不到已知的測試密碼;對存著的設定新增一個新密鑰欄位但不登記,回應必須仍遮蓋;送壞資料(例如損毀的 PDF、超長設定碼)使其失敗,回應 body 只含錯誤代碼,不含 stack、路徑、SQL 片段;把郵件伺服器位址改成不可達並按「寄測試信」,日誌搜尋測試密碼必須零命中 |
| 來源 | 掃描驗證:C02 D6(實例 M02-5、M22-2、M22-3、M04-12、M11-22)、C10 D3(實例 M16-2) |
| 欄位 | 內容 |
|---|---|
| 要求 | 前門(nginx)必須對所有回應加上:Content-Security-Policy——腳本只准來自本站、禁止 inline script;Strict-Transport-Security(HSTS)——讓瀏覽器記住永遠走 https;X-Frame-Options/frame-ancestors——不讓本站被嵌進別人的頁面;X-Content-Type-Options: nosniff——瀏覽器不得自行猜內容型別。標頭在前門統一加,不靠各頁各回應自己加 |
| 為什麼 | 別人的程式在本站網域執行(上傳的網頁檔被預覽、回呼頁網址參數進頁面)時,沒有全站 CSP 就沒有第二道牆擋住;沒有 HSTS,第一次打 http 那一下可被攔截;沒有 frame 限制,本站可被嵌進惡意頁面做點擊劫持。這也是資安問卷必問項 |
| 適用連線 | C01 瀏覽器 → 前門(標頭在這裡加);推及 C02(所有 API 與預覽回應經前門送出)、C04(OAuth 回呼頁,不需登入的伺服器渲染頁) |
| 對應威脅 | C01 T3 不需登入的頁面把網址參數放進頁面程式 🟠、C01 T4 回程把別人上傳的內容當網頁交給瀏覽器執行 🟠——這兩種手法已有掃描實例,但本條屬兜底:「個別修好後,標頭讓同類手法繞過第一道防線時仍被瀏覽器擋」,本身無掃描實例 |
| 驗證方式 | 對前門任一 URL(含 404 頁、API 回應、靜態檔)發 curl -I,回應必須同時帶四個標頭,CSP 不得含 unsafe-inline 與 * 來源;以 http 開 :80 必須只回 301;用 <iframe src="https://本站"> 嵌入測試頁,瀏覽器必須拒絕載入;上傳 .html 改名 .png 後預覽,回應必須帶 nosniff。標頭覆蓋率用腳本對路由清單逐一檢查,不抽樣 |
| 來源 | 標準做法:C01 D5◇、C01 D6◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 推到第三方頻道(Discord、Telegram、外部問題單)的內容必須最小化:只說「有事發生、請到系統查看」,不得帶客戶內部的專案名、人名、附件、截圖。使用者自填、可能夾帶客戶內部資料的內容(意見回饋、附件)送進外部系統前必須先提醒或過濾 |
| 為什麼 | 頻道與外部問題單是第三方雲端服務:推出去的內容就存在對方伺服器,客戶的專案名稱、人名、截圖含個資的附件一旦送出就無法收回,且合規問卷必問「資料是否流到第三方」 |
| 適用連線 | C16 api → 聊天 webhook、C15 api → 外部問題單 |
| 對應威脅 | 無掃描實例(標準做法)。相關手法:C16 T3 webhook 網址外流後冒充系統發話(無掃描實例)——頻道內容越少,網址外流時可被讀走的越少 |
| 驗證方式 | 觸發每一種會推到 Discord/Telegram 的事件(任務指派、專案啟動、批次完成),檢查實際送出的 HTTP body:必須不含測試專案名、測試人員暱稱與任何檔名;送出意見回饋含附件至外部問題單前,畫面必須有「內容會送到第三方」的提示,或附件被過濾 |
| 來源 | 標準做法:C16 D5◇、C15 D4◇ |
| 欄位 | 內容 |
|---|---|
| 要求 | 資料送到外部 AI 服務的範圍必須有清單:哪些功能會把哪類資料送到哪家 AI,寫在設定頁或文件,客戶看得到。送內文片段(而非整份)的功能,片段怎麼切、切多長必須說得出來並與實際行為一致 |
| 為什麼 | 客戶要簽核「資料是否跨境、是否由第三方處理」時,若答不出來送了什麼,就無法通過合規問卷,也無從判斷自家敏感內容是否外流;片段規則說不清楚,客戶無法評估單次最多送出多少 |
| 適用連線 | C13 api → 外部 AI |
| 對應威脅 | 無掃描實例(標準做法)。相關手法:C13 T4 AI 儀表板這條路不檢查權限,資料整包送出去 🟡——該手法已有實例(無法納入本條來源),本條是「讓客戶有能力發現送出範圍」的透明面 |
| 驗證方式 | 逐功能(證據自動分類、AI 儀表板、聊天框)抓實際送往 AI 閘道的請求 body,欄位與長度必須落在清單所列範圍內;清單中的功能數與實際呼叫外部 AI 的程式進入點數一致(新增進入點時清單未更新要被 review 擋下);設定頁或文件必須能指出「分類功能送的是內文片段,上限 N 字」 |
| 來源 | 標準做法:C13 D7◇ |
來源:連線頁的防線(D);去重對照在 requirements/_drafts/D-to-SR.md。