歡迎光臨
我們一直在努力

漏洞根因:字串拼接、資料型別與信任邊界

安全提醒:本文為不可部署的程式碼審計片段;測試僅限自有或明確授權環境。

「有過濾」、「欄位是數字」或「已經用了 PDO」都不等於查詢安全。真正要確認的是外部資料在資料庫解析 SQL 之前,能不能改變語法結構。

信任邊界與資料角色技術流程圖
信任邊界與資料角色:依序追蹤資料與安全控制點。

本篇會學到什麼

  • 字串拼接、型別假設與信任邊界如何一起造成漏洞。
  • 值 placeholder 為何不能代替欄位名。
  • 參數化、允許清單與最小權限各自解決什麼問題。

必備名詞與心智模型

Source 是外部資料來源,transform 是解碼、轉型或拼接,sink 是執行 SQL 的 API。Taint tracking 的核心問題是:不可信資料是否在沒有安全邊界的情況下抵達 sink。數字欄位也可能被直接修改;只有伺服器端明確轉型與範圍檢查才有意義。

發生情境與生活化比喻

字串拼接像把旅客的留言直接印在登機指令上;參數化像把留言放進封好的行李欄位。排序欄位則像選航線,不能把任意文字當行李處理,必須讓旅客從既定航線代碼中選擇。

不安全的原始碼

$category = $_GET['category'] ?? '';
$sort = $_GET['sort'] ?? 'name';
$sql = "SELECT id,name,price FROM products "
     . "WHERE category='" . $category . "' ORDER BY " . $sort;

$category 位於資料值,$sort 位於 SQL 結構;兩者需要不同處理。只對 category 做 escaping 仍留下 sort 風險。只在前端提供下拉選單也不安全,因為請求可被直接修改。

逐步看懂資料如何變成查詢

  1. 來源:兩個 GET 參數。
  2. 轉換:沒有伺服器端型別或 mapping。
  3. sink:query 執行完整字串。
  4. category 應變成參數值。
  5. sort 應先映射到程式內固定片段。
  6. 再檢查連線帳號是否只有 SELECT 權限。

修補後原始碼

$allowedSorts = [
    'name' => 'name ASC',
    'price_asc' => 'price ASC',
    'price_desc' => 'price DESC',
];
$orderBy = $allowedSorts[$_GET['sort'] ?? 'name'] ?? $allowedSorts['name'];
$statement = $pdo->prepare(
    "SELECT id,name,price FROM products WHERE category=:category ORDER BY {$orderBy}"
);
$statement->execute(['category' => $_GET['category'] ?? '']);

這裡的動態片段只可能來自程式碼內三個固定值。PDO 文件也指出 placeholder 代表完整資料 literal,不能拿來綁定關鍵字、欄位名或任意查詢片段。

如何驗證修補

  • 三個合法排序代碼得到預期順序。
  • 未知、空白與大小寫變體回到安全預設。
  • category 中的引號、Unicode 與長字串只作為值。
  • 程式碼掃描找不到 request 值直接進入 SQL 插值。
  • 資料庫帳號無建表、刪表與管理權限。


閱讀提醒:以下分析的目的,是讓你能在自己的程式、測試資料與授權環境中辨識風險。面對正式系統時,先取得明確授權並保存變更紀錄;不要用錯誤訊息或一次回應就推論資料外洩,也不要把文章中的概念改造成自動化探測。安全工作的完成條件,是能說明根因、修補位置、回歸結果與剩餘風險。

更多應用情境、常見誤判與觀察方法

把原理放回真實開發情境

姓名與搜尋詞是資料值;欄位名、排序方向和資料表名屬於 SQL 結構,兩者需要不同控制。 實作時不要只盯著畫面上的輸入框,還要檢查 API 參數、伺服器端預設值、資料轉換與最後呼叫的資料庫介面。最實用的閱讀方式,是把每一段程式標成「外部來源、轉換、控制、資料庫 sink」,確認資料值沒有在途中重新變回 SQL 結構。

常見誤判

只做跳脫或只檢查單引號,會忽略數字、編碼、動態識別字與二次使用。 安全判斷不能只靠畫面、單次錯誤或某一個防護產品;應同時看原始碼、驅動程式實際執行方式、資料庫權限與回歸測試。若無法證明查詢結構固定,就應把它視為待修的設計風險。

開發與 SOC 可以觀察什麼

Code review 應由資料來源一路追到 query API,並標記每一次字串串接與型別轉換。 日誌宜記錄時間、路由、請求關聯 ID、查詢名稱、結果狀態與耗時,敏感值則遮罩或雜湊。偵測規則的用途是縮短發現時間;阻擋之後仍須回到程式碼修補,並搜尋其他共用元件與相同資料流。

審查時的三個追問

  1. 這個值最早由誰控制,經過哪些轉換?
  2. 它在資料庫呼叫中是資料值,還是欄位、排序、運算式等結構?
  3. 若預防失效,最小權限、監控與事件流程能限制並發現多少影響?

開發與維運防禦清單

  • 禁止用黑名單猜測危險字元。
  • 同一資料只正規化一次,再做型別與業務規則驗證。
  • 程式碼審查搜尋 query()、raw SQL、字串插值與 stored procedure 內的動態 SQL。
  • 記錄拒絕原因與事件 ID,不把 SQL 原文回傳前端。

重點整理與下一篇

值、識別字與 SQL 片段不是同一種東西。值使用參數化,有限選項使用允許清單,權限限制漏洞發生後的影響。下一篇將用登入框說明查詢邏輯與身分驗證為何特別敏感。

參考資料與更新日期

更新日期:2026-07-20

贊(0) 贊助
未經允許不得轉載:波波的寂寞世界 » 漏洞根因:字串拼接、資料型別與信任邊界

波波的寂寞世界

Facebook聯繫我們

覺得文章有幫助,歡迎贊助支持本站

感謝你的支持,我會持續整理資安筆記、實務經驗與有價值的技術內容。

贊助本站