iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Build on Google AI

30 天打造 AI Web Security Agent:從 Google AI Studio 到 Gemini Agent系列 第 23 篇

Day 23|五種分類放進同一包,不代表只剩安全與不安全

  • 分享至 

  • xImage
  •  

前言

Day 22,我讓工作台每次都從保存來源重新驗證 5 種情境、15 組案例。接下來的問題不是「怎麼把 JSON 接在一起」,而是「怎麼讓不同實驗能一起查詢,又不改掉各自的語意」。

最省事的做法,是替每組資料加一個 safe 或 unsafe。但這正好會破壞前 20 天留下的差異:未反射、fragment 沒被頁面使用、輸入已儲存但顯示為文字,以及提交遭拒,都沒有觀察到固定探針執行,原因卻完全不同。Day 23,我建立統一的 evidence bundle,同時保留 tool_verdict 和 canonical_outcome,拒絕把所有結果壓成二選一。

Bundle 先描述範圍,再放案例

Evidence Bundle v1 的頂層不是只有案例陣列。它先記錄 schema_version、產品、處理範圍和摘要,再放入入口盤點、5 種情境、發布關卡與解讀限制。contexts 裡的每個情境都有原實驗日、顯示名稱、scenario ID、XSS 類型、來源摘要路徑與 SHA-256。

案例 ID 採用 day-<日>-<組別>。例如 Day 14 的弱點組是 day-14-vulnerable,Day 18 的拒絕組是 day-18-rejected。這樣即使不同實驗都使用 vulnerable,整份 bundle 仍不會撞名,也不必靠陣列位置猜來源。

一組案例的核心資料如下:

{
  "id": "day-14-safe",
  "name": "safe",
  "tool_verdict": "fragment_rendered_as_text",
  "canonical_outcome": "rendered_as_text",
  "execution_observed": false,
  "response_sha256": "…",
  "form_sources": []
}

response_sha256 讓案例回到原始回應,POST 與儲存型案例另保留表單來源;報告驗證資料也掛在同一組案例下,但不覆蓋工具觀察。這些欄位讓 bundle 成為索引,而不是把原始檔重新包裝後丟掉路徑。

原分類逐字保留,標準化結果另開一欄

目前 15 組案例共有 12 種原始分類。我用明確對照表產生 8 種標準化結果:

tool_verdict canonical_outcome
confirmed_xss execution_confirmed
confirmed_dom_xss execution_confirmed
confirmed_post_reflected_xss execution_confirmed
confirmed_stored_xss execution_confirmed
reflected_but_not_executed reflected_not_executed
not_reflected、post_not_reflected not_reflected
fragment_rendered_as_text rendered_as_text
fragment_not_rendered source_not_used
post_reflected_as_text reflected_as_text
stored_as_text stored_as_text
submission_rejected submission_rejected

這裡只有 4 種已確認執行分類被合併為 execution_confirmed,因為跨情境統計時,我確實想知道固定探針在哪幾組執行;原本是哪一種 XSS,仍由情境的 xss_kind 與逐字保留的 tool_verdict 表達。

其餘結果沒有硬湊。例如 fragment_not_rendered 代表頁面沒有把 fragment 放進目標內容,post_not_reflected 代表 POST 值沒有出現在結果回應,submission_rejected 則是提交已被拒絕。它們都不是 execution_confirmed,卻也不能互換。

如果未來 detector 新增一個對照表裡沒有的 verdict,工作台會中止並要求我明確決定映射,而不是依字串猜成「可能安全」。這個 fail closed 行為能避免新語意悄悄被舊分類吞掉。

「未觀察到執行」不是共同結論

摘要顯示 5 組觀察到固定探針執行、10 組未觀察到。這個數字適合做整體導航,卻不適合單獨當結論。我要知道某一組為什麼未執行,仍須看 tool_verdict、canonical_outcome、情境、回應雜湊和來源檔。

例如 Day 14 的純文字組是 rendered_as_text,表示 fragment 確實進入目標 DOM,但透過 textContent 顯示;Day 14 的忽略組是 source_not_used,目標內容根本沒使用 fragment。兩組的 execution_observed 都是 false,資料流卻停在不同位置。若只留下 false 或 safe,後面便無法重建這個差異。

同樣地,canonical_outcome 也不是正式風險等級。它描述本次固定探針的技術結果,不知道真實資產、使用者、權限、資料敏感度或部署控制。工作台頂層因此保留 interpretation_limits,提醒「未觀察到」不等於網站安全。

同一份來源應該產生同一個 bundle

Day 20 的 portfolio 帶有建立時間,但時間不是證據內容。我在標準化時沒有把它帶進 bundle,JSON 輸出則固定使用 UTF-8、相同縮排與鍵名排序。如此一來,相同來源不會只因執行時間不同就改變雜湊。

我執行工作台測試,發布合約確認 5 種情境、15 組案例、6 份表單和執行訊號數量完全符合;另一個測試則在兩個暫存目錄各建立一次,逐位元比較 bundle、Markdown、HTML 與 manifest,結果一致。可重現輸出讓後面的 SHA-256 有實際意義。

Day 23 的成果不是替 15 組資料貼上更簡單的標籤,而是建立兩層語言:tool_verdict 保存當時工具真正說了什麼,canonical_outcome 提供跨情境查詢。明天,我會把 5 個固定的 AI 報告批次接進這個結構,重新執行各日 validator,並把自動驗證和作者語意核對分開呈現。

那就…
明天見!


上一篇
Day 22|重新相信保存結果以前,我先把來源重驗接回來
下一篇
Day 24|AI 報告通過 Schema 之後,為什麼我還要逐份核對?
系列文
30 天打造 AI Web Security Agent:從 Google AI Studio 到 Gemini Agent 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言