母案:FR-058 檢測工具擴充(四工具接入)— FR-058 檢測工具擴充(四工具接入)(母案)
起源子需求:FR-058.1 ZAP(DAST 網頁動態掃描)— FR-058.1 ZAP(DAST 網頁動態掃描)
本案為 FR-058 第一批出貨後的後續另案(決策 D12,2026-07-30 拍板)|Repo:BE + evidence-agent
FR-058.1 ZAP 的登入後主動掃描,param_schema 設計為傳統表單登入模型——login_url / login_username / login_password / logged_in_indicator 四欄。ZAP 對登入頁 POST 帳密欄位、用 cookie 維持 session、用 logged_in_indicator 比對回應內容判定登入態。
2026-07-30 對一個 Next.js SPA 站台實測,發現這個模型對 SPA 天生不成立。三個原因彼此獨立,必須同時解決才會通:
| # | 現象 | 根本原因 | SPA 需要的做法 |
|---|---|---|---|
| ① | 填了帳密但 ZAP 從未登入成功 | SPA 的登入是 JS 呼叫 API(如 POST /api/.../login)取 token,頁面上沒有傳統表單提交可供 ZAP 對付。ZAP 的 form-based 認證對 SPA 不會發生作用 |
json-based 認證(對登入 API 送 JSON payload) |
| ② | 就算登入成功,後續請求仍是未登入身分 | SPA 多用 JWT 存 localStorage、靠 Authorization header 帶;ZAP 預設 session 管理是 cookie-based,不會把 token 塞進後續請求 |
script-based session management(需撰寫並上傳 ZAP script) |
| ③ | ZAP 誤判未登入、反覆重跑登入 | logged_in_indicator 比對的是 HTTP 回應的原始內容;SPA 初始 HTML 是空殼,登入後才出現的文字是 JS 渲染後才進 DOM 的,原始回應裡找不到 |
改用 API 回應特徵或其他非 DOM 判定(前兩項未解時此項無意義) |
第一批的處置:文件與 setup_guide 明白標示「登入後掃描僅支援傳統表單登入」,避免使用者對 SPA 填了帳密卻得到與匿名掃描相同的結果而誤以為是故障。
| 項目 | 內容 | Repo |
|---|---|---|
param_schema 擴充 |
加「認證方式」選擇欄(表單登入 / json 認證),並依選擇條件顯示對應參數(json 認證需要登入 API 端點、payload 欄位名對應、token 取出路徑等) | BE(seed migration) |
| json-based 認證接線 | connector 依認證方式分支,呼叫 ZAP 的 json-based authentication 設定 API(舊參考碼 auto_pentest/domain/zap/service/zap_auth.py 有四種認證方式的 API 序列可參考邏輯) |
evidence-agent |
| script-based session management | 需撰寫並上傳 ZAP script——把 token 從登入回應取出、塞進後續請求的 Authorization header。注意 script engine:Oracle Nashorn 在 JDK 15 後已移除,ZAP 新版預設用 Graal.js(舊碼 java_script() 還停在 Nashorn,是會踩到的雷) |
evidence-agent |
| 登入態判定 | logged_in_indicator 對 SPA 不可靠,需改用 API 回應特徵或其他非 DOM 判定方式 |
evidence-agent |
| SPA 測試站台 | 需要一個可重複驗證的 SPA 目標(實測用的是 Next.js 站台),用來驗證認證 + session + 掃描深度整條鏈路 | 測試環境 |
以第一批的表單登入模型對該 SPA 做掃描,結果等同匿名掃描:
_next/static 下的 JS / CSS chunk、favicon;無任何 API 端點、無任何登入後頁面。這組數字同時是匿名掃描的價值邊界的具體證據:對 SPA 而言,未解決登入即等同匿名掃描——能查出組態層問題,但碰不到應用邏輯。這正是登入後掃描在稽核場景的價值所在,也是本案值得列為獨立後續案、而非在第一批做半套的理由。