本系列不要求讀者架設靶場。每篇都沿用同一間虛構商店,逐格閱讀「輸入 → 變數 → 查詢模板 → 參數 → 結果」,讓初學者先建立可重複使用的分析方法。

本篇會學到什麼
- 認識 users、products、orders 三張虛構資料表。
- 分辨值參數與 SQL 結構。
- 用五個問題審查任何資料庫功能。
必備名詞與心智模型
users 保存合成帳號 [email protected];products 保存名稱與價格;orders 保存訂單歸屬。Request 是外部輸入,variable 是程式暫存值,query template 是固定 SQL,parameter 是分離傳入的資料,result 是資料庫回傳。
發生情境與生活化比喻
把每個案例當成透明水管:不同入口的水最後可能流到同一個資料庫 sink。表單看起來最明顯,但 Cookie、Header、匯入檔與排程工作只是不同入口。分析時不要只盯著畫面,要沿資料流往下追。
不安全的原始碼
$term = $_GET['q'] ?? '';
$sql = "SELECT id, name, price FROM products "
. "WHERE name LIKE '%" . $term . "%'";
片段只供閱讀。它沒有連線設定與 HTTP 應用骨架,不能直接部署。錯誤點是搜尋詞被插入 SQL 文字,而不是搜尋功能本身。
逐步看懂資料如何變成查詢
- 先圈出來源:
$_GET['q']。 - 標出中間變數:
$term。 - 找資料庫 sink:
$sql將送往 query API。 - 把輸入替換成
O'Reilly 入門書,觀察一般單引號也會破壞字串。 - 判斷輸入位於值、識別字還是完整 SQL 片段。
修補後原始碼
$term = $_GET['q'] ?? '';
$statement = $pdo->prepare(
'SELECT id, name, price FROM products WHERE name LIKE :term'
);
$statement->execute(['term' => '%' . $term . '%']);
百分比是搜尋需求的一部分,可在資料值中組合;SQL 結構仍固定。若要讓使用者選排序,應把 price_desc 映射成程式內固定的 price DESC。
如何驗證修補
準備正常中文、空字串、超長字串、含單引號名稱與未列入允許清單的排序代碼。驗證正常搜尋保持可用、特殊字元不產生錯誤、未知排序回到安全預設值,且日誌不記錄密碼或完整敏感參數。
閱讀提醒:以下分析的目的,是讓你能在自己的程式、測試資料與授權環境中辨識風險。面對正式系統時,先取得明確授權並保存變更紀錄;不要用錯誤訊息或一次回應就推論資料外洩,也不要把文章中的概念改造成自動化探測。安全工作的完成條件,是能說明根因、修補位置、回歸結果與剩餘風險。
更多應用情境、常見誤判與觀察方法
把原理放回真實開發情境
把每次練習限制在本機測試資料與固定案例;先畫出 request、variable、query template、parameter、result,再閱讀程式。 實作時不要只盯著畫面上的輸入框,還要檢查 API 參數、伺服器端預設值、資料轉換與最後呼叫的資料庫介面。最實用的閱讀方式,是把每一段程式標成「外部來源、轉換、控制、資料庫 sink」,確認資料值沒有在途中重新變回 SQL 結構。
常見誤判
看到特殊字元造成錯誤,不代表已證明注入;也可能是編碼、驗證或一般程式例外。 安全判斷不能只靠畫面、單次錯誤或某一個防護產品;應同時看原始碼、驅動程式實際執行方式、資料庫權限與回歸測試。若無法證明查詢結構固定,就應把它視為待修的設計風險。
開發與 SOC 可以觀察什麼
保留測試案例、查詢名稱與錯誤事件編號,避免記錄密碼、Token 或完整個資。 日誌宜記錄時間、路由、請求關聯 ID、查詢名稱、結果狀態與耗時,敏感值則遮罩或雜湊。偵測規則的用途是縮短發現時間;阻擋之後仍須回到程式碼修補,並搜尋其他共用元件與相同資料流。
審查時的三個追問
- 這個值最早由誰控制,經過哪些轉換?
- 它在資料庫呼叫中是資料值,還是欄位、排序、運算式等結構?
- 若預防失效,最小權限、監控與事件流程能限制並發現多少影響?
開發與維運防禦清單
- 每個案例寫出 source、transform、sink。
- 值用 bind parameter;識別字用固定 mapping。
- 驗證格式與長度是額外防線,不取代參數化。
- 錯誤訊息對外一致、對內可追蹤。
重點整理與下一篇
之後看到任何案例,先問輸入從哪裡來、經過什麼轉換、最後進入哪個 API、位於 SQL 的哪種位置、資料庫帳號擁有什麼權限。下一篇會深入字串拼接、資料型別與信任邊界。
參考資料與更新日期
更新日期:2026-07-20










