iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Build on Google AI

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

Day 14|原始回應沒有探針,瀏覽器裡還會發生 XSS 嗎?

  • 分享至 

  • xImage
  •  

前言

Day 12,我測試伺服器把 q 放進行內 JavaScript 字串時,探針會不會跳出字串。Day 13 再把原始回應與瀏覽器執行證據交給 AI,檢查報告能否保留差異。這兩天的輸入都隨 HTTP 請求到達伺服器,原始回應也是重要證據。

今天換成瀏覽器端的資料流:我把探針放在網址 # 後的片段,讓前端 JavaScript 讀取,再寫進頁面。

這次我只測 3 個本機頁面:同一段片段輸入進入 innerHTML、進入 textContent,以及完全不被頁面使用。我要分開回答「伺服器看見什麼」「DOM 建立了什麼」和「探針是否執行」。

從網址片段讀入,再決定怎麼寫

我在 3 個頁面都放了 <p id="result"></p>。前兩頁使用同一行程式,從 #q=... 讀取 q:

const value = new URLSearchParams(location.hash.slice(1)).get('q') ?? '';

兩頁只在寫入目標元素的方式不同;第三頁則完全不讀取片段:

頁面 寫入方式 本次要觀察的差異
/dom-vulnerable output.innerHTML = value 輸入會不會被解析成 HTML 元素
/dom-safe output.textContent = value 完整輸入能否只作為文字顯示
/dom-ignored output.textContent = '固定內容' 片段存在時,目標元素是否仍不顯示它

innerHTML 會解析收到的字串並建立 DOM 元素;textContent 用於純文字內容,不把其中的標籤當成 HTML。

探針為什麼使用圖片錯誤事件?

我給每組測試一個獨立識別碼,並把以下固定形狀的探針放進 fragment 的 q:

<img src="/day14-missing.png" alt="" onerror="document.documentElement.setAttribute('data-day14-xss','本次識別碼');alert(1)">

圖片路徑是本機刻意不存在的檔案。如果這段文字真的被解析成 <img>,載入失敗就會觸發 onerror。我要求 Chrome 同時捕捉到訊息為 1 的 alert,並在 <html> 讀回與本次識別碼相同的 data-day14-xss,才把本次探針標為已執行。只有圖片元素、只有對話框,或只有旗標,都不足以通過這個判定。

這裡沒有用 <script> 當探針。MDN 指出,經 innerHTML 插入的 <script> 元素不會因此執行,但事件處理屬性仍可能執行。若只拿 <script> 測試,沒有跳出對話框可能導致錯誤結論。

原始回應與伺服器請求都沒有探針

程式暫時在本地的 127.0.0.1 啟動網站,先保存每頁的原始 HTML 回應,再讓 Chrome 開啟含有 #q=... 的網址。3 頁都回傳 200 與 text/html; charset=utf-8;本次環境是 Python 3.14.4、Google Chrome 153.0.8010.36。

三份原始回應都沒有各自的探針識別碼。本機伺服器記下的 HTTP request target 也只有 /dom-vulnerable、/dom-safe、/dom-ignored 等路徑,沒有 #q=...。弱點頁另有 /day14-missing.png 的 404 請求,因為瀏覽器後來建立了探針圖片;這是圖片請求,不是原始頁面請求帶入了 fragment。Chrome 也可能請求 /favicon.ico。

因此,「原始回應沒有探針」在這次只能證明伺服器沒有把本次識別碼放進 HTML。它不能回答前端腳本是否把片段輸入放進 DOM。

Chrome 裡的 3 種結果

弱點頁的瀏覽器從 fragment 讀回完整探針,#result 中形成了真正的 <img>,其獨立 onerror 屬性包含本次識別碼。Chrome 捕捉到 alert(1),而 <html> 的 data-day14-xss 是 day14-5f8c23553468a3c0,與送出的識別碼一致。依前面的雙重條件,本次固定探針在這個本機頁面上執行,分類為 confirmed_dom_xss。

文字寫入頁也從 fragment 讀回完整探針,但 #result 的 textContent 就是整段字面文字;讀取其 innerHTML 時,開頭的 <img 呈現為 &lt;img。DOM 沒有建立圖片元素,也沒有 alert 或相符旗標。本次分類是 fragment_rendered_as_text,不能把「畫面上看得到 onerror 文字」寫成「事件處理屬性已形成」。

忽略片段頁的網址同樣帶著探針;檢查程式可以從瀏覽器位置讀到它,但頁面腳本只寫入「固定內容」,沒有讀取 fragment。#result 沒有本次探針,也沒有執行訊號,因此分類為 fragment_not_rendered。這與文字寫入頁的「有顯示,但只作為文字」是兩種不同結果。

組別 原始回應含探針 目標 DOM alert(1)/相符旗標 分類
innerHTML 否 建立帶 onerror 的 <img> 兩者都有 confirmed_dom_xss
textContent 否 完整探針文字,沒有 <img> 兩者都沒有 fragment_rendered_as_text
忽略片段 否 固定內容 兩者都沒有 fragment_not_rendered

完整原始回應、每組 JSON、SHA-256、伺服器收到的請求路徑和摘要都保存在 day-14/results/。我也執行了 4 個本機瀏覽器與輸入限制測試,全部通過;測試涵蓋探針未進入 HTTP 回應、DOM 結構、雙重執行訊號,以及拒絕遠端目標與無效識別碼。

Day 14:分類要跟著資料流走

這次的關鍵不在回應裡搜尋 alert(1)。3 頁的原始回應都沒有探針,只有弱點頁的前端程式把 fragment 送進 innerHTML,讓它變成帶事件處理屬性的 DOM 元素。

本次直接支持的結論只限於本機 URL fragment 的 q、這 3 個 DOM 寫入情境和固定的 img onerror 探針。沒有測試其他 DOM 來源、其他寫入點、CSP、真實使用者或正式風險等級;textContent 頁與忽略片段頁的未執行結果,也不能外推為整站安全。今天沒有把結果交給 AI 產生風險報告,先把瀏覽器端的證據留清楚。

那就…
明天見!


上一篇
Day 13|把 JavaScript 字串證據交給 AI,報告能分清誰在執行嗎?
下一篇
Day 15|把網址片段交給 AI,報告能分清「讀到」與「執行」嗎?
系列文
30 天打造 AI Web Security Agent:從 Google AI Studio 到 Gemini Agent 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言