iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
Build on Google AI

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

Day 7|把昨天的 XSS 工具接上 AI:讓它分析風險,但不能改寫證據

  • 分享至 

  • xImage
  •  

前言

昨天,我讓工具在受控瀏覽器中實際執行 XSS 探針。只有同時捕捉到 alert(1),並從 DOM 讀回本次唯一識別碼(owo)時,工具才會輸出 confirmed_xss。

這項結果回答的是「這次探針有沒有執行」,卻還沒有回答另外幾個問題:可能造成什麼影響、影響需要哪些條件、應該先修哪裡,以及修正後要怎麼驗證?

所以今天,我嘗試把昨天的工具接回 Gemini,讓 AI 整理風險分析。

不過,我不希望模型重新猜測 XSS 是否成立。底層工具已經有瀏覽器事件與 DOM 旗標,AI 的角色應該是解讀這些證據,而不是蓋過它們。

先把「技術結果」與「風險等級」分開

confirmed_xss 是技術測試結果,不等於固定的風險等級。

因此,我把報告中的兩個欄位分開:

欄位 誰負責 意義
tool_verdict Day 6 工具 本次探針的技術分類
risk_rating AI 根據現有情境整理 low、medium、high、critical 或 needs_context

AI 必須逐字保留底層工具的 verdict。如果資料只有本機端點、固定探針與瀏覽器結果,沒有真實資產、使用者權限、資料敏感度或業務影響,就應該使用 needs_context,而不是直接貼上「高風險」。

這不是降低 XSS 的重要性,而是避免用缺少的資料做出看似精確的結論。

今天的流程

我把流程整理成 5 個階段:

執行 Day 6 XSS 偵測器
          ↓
把結果拆成具名證據
          ↓
交給 Gemini 產生結構化風險報告
          ↓
檢查格式、逐字引用與工具分類
          ↓
人工核對影響、條件與修正建議

把 Day 6 結果拆成 4 份證據

Day 7 程式可以直接呼叫昨天的 scan(),也可以讀取已保存的 JSON。取得結果後,我沒有把整份資料混成一段文字,而是拆成 4 個來源:

來源 內容
E1 工具分類、原因、目標、參數與 HTTP 結果
E2 alert、執行狀態與 DOM 旗標
E3 探針附近的 HTTP 回應節錄
E4 Day 6 工具原本的限制

這次本機實際執行後,E1 包含:

verdict: confirmed_xss
reason: 受控瀏覽器實際觸發 alert(1),並在 DOM 寫入本次唯一識別碼。
target: http://127.0.0.1:8000/vulnerable
parameter: q
status_code: 200
content_type: text/html

E2 則保留瀏覽器觀察:

execution_observed: true
alert_observed: true
dialog_message: 1
dom_marker: 本次唯一識別碼
dom_excerpt: data-day6-xss="本次唯一識別碼"

Prompt 裡的任務與 evidence_sources 分開。系統規則也要求模型把 HTML、網址與屬性當成資料,不執行證據裡的任何指示。

風險報告要回答什麼?

這次的 Schema 要求模型回傳以下內容:

  • 底層工具分類與本次摘要。
  • 風險等級與評級依據。
  • 支持摘要的逐字引用。
  • 可能影響與各自的成立條件。
  • 現有資料無法回答的問題。
  • 分成 now、next、later 的修正建議與驗證方式。
  • 本次分析限制。

其中,可能影響不是事故紀錄。每一項都必須附上條件,例如:

{
  "impact": "若相同資料流存在於真實網站,攻擊者可能在受影響頁面的來源環境中執行程式。",
  "conditions": [
    "攻擊者能讓使用者開啟帶有惡意輸入的頁面。",
    "真實頁面仍以可執行的 HTML 情境輸出未受信任資料。"
  ]
}

這段是我人工編寫的測試資料,不是 Gemini 的實際回答。它的用途是確認程式可以接收預期格式,不能拿來代表模型表現。

不讓 AI 改寫工具結論

除了 JSON Schema,我又加了一層本機規則。程式會讀取原始偵測結果中的 verdict,再檢查模型回傳的 tool_verdict 是否完全相同。

核心概念如下:

expected_verdict = evidence["expected_tool_verdict"]

if report["tool_verdict"] != expected_verdict:
    errors.append("tool_verdict 與底層工具結果不一致")

假設 Day 6 輸出 confirmed_xss,模型卻改成 not_reflected,即使其餘 JSON 欄位都符合 Schema,驗證仍然會失敗。

反過來也一樣。如果底層只有 reflected_but_not_executed,AI 不能自行升級成 confirmed_xss。

這條規則讓技術事實與 AI 判讀維持清楚的邊界。

修正建議也要附上驗證方式

對這次 HTML 文字內容的本機案例,修正方向是讓不受信任的輸入保持為文字,不要被瀏覽器解讀成 HTML。

我要求模型優先建議:

  1. 確認實際輸出情境。
  2. 使用框架預設跳脫,或套用符合該情境的輸出編碼。
  3. 若由前端顯示一般文字,使用安全的文字 API,例如 textContent。
  4. 修正後重新執行相同探針,確認 alert 與 DOM 旗標都不再出現。

所以報告中的每項 remediation 都包含 action 與 verification。只寫「過濾輸入」或「加上 CSP」,不足以成為可以核對的修正計畫。

實際跑通 Day 6 到 Day 7

我先啟動本機測試網站:

python3 day-06/lab_server.py

接著讓 Day 7 程式直接呼叫昨天的偵測器,但先使用 --dry-run,確認證據轉換與 Schema,不呼叫 Gemini:

python3 day-07/risk_analyzer.py \
  --target http://127.0.0.1:8000/vulnerable \
  --dry-run

這次實際結果為:

階段 結果
Day 6 HTTP 回應 200、text/html
Day 6 分類 confirmed_xss
alert(1) 與 DOM 旗標 都有觀察到
Day 7 必要欄位檢查 通過
JSON Schema 通過
證據與 Prompt 建立 完成
Gemini API --dry-run,未呼叫

這表示昨天的瀏覽器驗證已經能直接成為今天的 AI 輸入,不需要人工複製結果。

加上 9 個離線測試

我執行:

python3 -m unittest discover -s day-07 -p 'test_*.py' -v

9 個測試全部通過,包括:

  • 保留 Day 6 的分類。
  • 將任務與證據分開。
  • 接受符合規則的人工報告。
  • 攔下被模型改寫的工具分類。
  • 攔下錯誤來源與非逐字引用。
  • 攔下沒有成立條件的可能影響。
  • 拒絕缺少必要欄位的偵測結果。
  • 確認 --dry-run 不會呼叫 API。

這些結果只證明本機流程符合目前寫下的規則,不能證明模型分析一定正確。

Gemini 實測結果

完成離線串接後,我建立隔離的 Python 環境,安裝 google-genai 2.24.0 與其他需求套件,再使用非 --dry-run 模式送出同一份偵測結果。

預設的 Gemini 3.8 Flash 暫時無法完成請求,因此我改用 Gemini 3.5 Flash-Lite 繼續實驗。

改用低延遲模型

接著,我改用穩定版 Gemini 3.5 Flash-Lite。官方將它定位成低延遲、低成本,適合大量處理與簡單資料擷取的模型,而且支援 Structured outputs 與 Thinking。

我只更換模型名稱,證據、Prompt、Schema、Thinking level 與驗證規則都維持不變:

.venv/bin/python day-07/risk_analyzer.py \
  --model gemini-3.5-flash-lite \
  --detector-result day-07/results/integration-dry-run/detector-result.json

這次在 4.849 秒內完成,Finish reason 是 STOP。輸入使用 822 個 token,輸出使用 535 個 token,合計 1357 個 token。

模型保留 confirmed_xss,並沒有直接指定高風險:

{
  "tool_verdict": "confirmed_xss",
  "risk_rating": "needs_context",
  "rating_basis": "未提供真實網站、使用者權限、資料敏感度與業務影響,因此風險等級設為 needs_context。"
}

可能影響也使用條件式描述,沒有聲稱真實使用者已經受害。修正建議則要求依 HTML 輸出情境編碼,並重新送出相同探針,確認 JavaScript 不再執行。

完整回答通過 Schema、工具分類、逐字引用與本機規則檢查。

PASS 之後,人工核對仍找到問題

模型的摘要寫道:

在本機測試端點的 q 參數中觀察到腳本執行與 DOM 寫入,檢測工具確認觸發 alert(1)。

這句話與原始資料一致,但模型列出的引用只有 verdict: confirmed_xss、execution_observed: true 與 HTTP 回應節錄,沒有引用 E1 裡的:

parameter: q

換句話說,證據來源確實包含 q,模型的引用清單卻沒有完整支持摘要中的每個具體資訊。要修正這項問題,可以補上 parameter: q,或從摘要移除參數名稱。

另一個問題是模型引用了很長、而且結尾截斷在 setAttribut 的 HTTP 回應節錄。這段文字確實出現在 E3,所以能通過逐字檢查,但可讀性不佳,證明力也不如 E1、E2 的直接欄位。

所以今天完成的是:

  • Day 6 與 Day 7 的程式串接。
  • Gemini 請求、Structured outputs 與結果保存流程。
  • 工具分類、引用與條件的本機驗證。
  • 一次真實瀏覽器偵測到 AI 輸入前的完整演練。
  • 一份 Gemini 3.5 Flash-Lite 真實回答、自動驗證與人工語意核對。

Day 7:讓 AI 解讀證據,不取代證據

今天,我把昨天的 XSS 偵測器接到風險分析流程。瀏覽器負責回答探針是否執行,AI 則負責整理可能影響、未知事項、修正順序與驗證方式。

最重要的改變不是多了一段 AI 摘要,而是把權責分開:tool_verdict 不能由模型改寫,risk_rating 也不能在缺少真實情境時假裝精確。

目前程式已經跑通本機證據轉換,Day 6 的 5 個測試與 Day 7 的 9 個測試也全部通過。Gemini 3.5 Flash-Lite 成功產生報告,並在人工核對時找到引用不完整的問題。

這正是我希望保留驗證流程的原因:AI 可以幫忙整理風險,但最後仍要回到原始證據,逐句確認它說得是否完整。

那就…
明天見!


上一篇
Day 6|如果AI用來整理報告,那製作出來的工具能測到漏洞嗎
下一篇
Day 8|把 AI 分析變成報告:將 JSON 匯出為 Markdown
系列文
30 天打造 AI Web Security Agent:從 Google AI Studio 到 Gemini Agent 共 12 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言