前幾天,我依序檢查了 HTML 屬性、行內 JavaScript 字串,以及網址片段進入 DOM 的情境。這次我把輸入點換成表單。瀏覽器送出 method="post" 時,欄位資料會放在請求本文;回應是否把它放回 HTML,以及瀏覽器會不會把它建立為可執行元素,仍要分別檢查。
我在 127.0.0.1 建立 3 個只差在輸出處理的表單:未編碼反射、HTML 跳脫、完全不反射。每組都由 Chrome 開啟表單、填入固定探針並提交;伺服器只接受單一 q 欄位。這樣可以從「確實送達」一路追到「是否執行」,而不靠網址或回應裡的一個關鍵字猜結果。
三頁表單都使用明確的 action、method="post" 和 enctype="application/x-www-form-urlencoded"。我保存 GET 取得的原始表單 HTML,也從 Chrome 的 DOM 讀取 action、method 和欄位。後續可以只讀這些保存檔重新盤點表單,不必再次送出探針。
每次提交使用不同的 day16- token。探針以本機不存在的 /day16-missing.png 觸發圖片錯誤事件;事件只做兩件事:在文件根元素留下與 token 相同的旗標,並顯示 alert(1)。探針沒有外傳地址或資料。測試頁也只綁定 127.0.0.1。
我把伺服器讀到的 POST 本文原始位元組、請求行與標頭、結果頁原始 HTML、SHA-256,以及瀏覽器 DOM 分開保存。三組請求都符合以下事實:
request_method: POST
request_parameter: q
request_value_matches_payload: true
這只能證明表單把本次探針送到伺服器。要判斷反射或 XSS,還得往回應和 DOM 看。
未編碼頁把 q 直接插入 <p id="result"> 的 HTML 文字位置。原始回應含探針,Chrome 建立了 <img> 元素,隨後捕捉到訊息為 1 的對話框;文件根元素的旗標也與這次 token 相同。雙重訊號相符後,我把這一組歸為 confirmed_post_reflected_xss。
跳脫頁收到完全相同的欄位形式,但先對 q 做 HTML 跳脫。原始回應中,探針的 <img 開頭變成 <img;Chrome 顯示的是完整探針文字,沒有建立圖片,也沒有出現本次執行訊號。這組分類是 post_reflected_as_text。
未反射頁也收到了 POST 值,結果頁卻只顯示「固定內容」。原始回應不含該次 token,目標 DOM 不含探針元素,也沒有觀察到執行訊號,因此分類為 post_not_reflected。
| 頁面 | POST 值送達 | 原始回應含 token | DOM 建立 <img> |
雙重執行訊號 | 結果 |
|---|---|---|---|---|---|
| 未編碼反射 | 是 | 是 | 是 | 相符 | 確認本次固定探針執行 |
| HTML 跳脫 | 是 | 是,但特殊字元已跳脫 | 否 | 均無 | 探針只當文字顯示 |
| 未反射 | 是 | 否 | 否 | 均無 | 本次結果頁未顯示探針 |
這次的關鍵不是 POST 本身是否危險,而是伺服器如何處理收到的值,以及瀏覽器如何解讀結果。request_value_matches_payload: true 在三組都成立,只有未編碼反射頁出現探針元素與雙重執行訊號。因此,若只看請求本文,三組無法區分;只看原始回應是否含 token,也會把跳脫頁與弱點頁混在一起。
我把 3 組的原始表單、請求本文、回應、DOM 和執行訊號各自存檔。明天會只讀這些檔案,檢查 AI 風險報告能否保留「送達、反射、解析、執行」之間的差異。
本次結論只限於這 3 個本機表單、單一 q 欄位與固定探針。跳脫頁和未反射頁沒有觸發本次探針,不代表其他輸入或整個頁面安全;我也沒有測試儲存型 XSS、真實使用者或正式網站。
那就…
明天見!