CEH · M15

參數化查詢:讓資料保持為資料

SQL 注入發生在不可信輸入改變了查詢語法的邊界。固定查詢結構並綁定值,能把使用者文字留在資料的位置。

讀完後,你可以
  • 解釋字串拼接與參數綁定的差別。
  • 在記憶體 SQLite 範例驗證含引號的名稱。

先備閱讀:物件授權:知道報告 ID,不代表可以讀取

查詢語法與輸入值要分開

把輸入直接接進 SQL 字串,會讓資料中的引號或其他語法影響查詢解讀。參數化查詢先定義結構,再用資料庫介面的綁定機制傳入值;請依實際驅動程式的 placeholder 語法使用。

參數通常用於值,不能任意拿來代替資料表名、欄位名或排序方向。這些結構若真的需要動態變動,應從明確允許的固定選項映射,而不是直接接受任意字串。

延伸閱讀:OWASP: SQL Injection Prevention Cheat Sheet

參數化之外仍有其他邊界

參數綁定不會替你判斷使用者是否有權看那筆資料,也不會自動選擇資料庫帳號權限。授權、最小權限與錯誤處理仍需各自設計。

本練習用 SQLite 記憶體資料庫與一筆虛構名稱,觀察一般含引號文字如何被正確處理。它驗證這條查詢的值綁定,不代表所有程式路徑都安全。

延伸閱讀:Python: sqlite3 parameter substitution

例子:查詢 O’Neil 這個名字

用字串拼接時,一個正常姓名中的 ASCII 單引號也可能破壞 SQL 結構。下方程式用 ? 綁定值。

SQL 結構維持 name = ?;姓名由 execute 的第二個參數傳入。資料庫會把整個姓名當成值來比對。

判斷:預期取得唯一一筆合成資料,不需要手動移除引號。

離線練習:記憶體資料庫查詢

本機 Python 3 與 sqlite3 標準模組;不建立磁碟資料庫、不連線,也不使用真實個資。

  1. 閱讀下方程式,找出固定 SQL 與綁定值的位置。
  2. 在本機執行,核對輸出。
  3. 把查詢值改成不存在的名稱,預期空清單。
import sqlite3
con = sqlite3.connect(":memory:")
try:
    con.execute("CREATE TABLE people (name TEXT)")
    con.execute("INSERT INTO people VALUES (?)", ("O'Neil",))
    print(con.execute("SELECT name FROM people WHERE name = ?", ("O'Neil",)).fetchall())
finally:
    con.close()

預期結果

第一次輸出 [("O'Neil",)];查詢不存在名稱時輸出 []。

自行檢核

如果改用參數作資料表名稱,為什麼不是同一種綁定問題?

結束與清理

程式結束即關閉記憶體資料庫,不留下資料檔。

Q&A · 檢查你的理由

選一個答案與作答信心,再閱讀所有選項的解析。答案只儲存在此瀏覽器。

ceh-m15-sql-q1 · 原創練習

參數綁定的主要目的為何?

參數綁定的主要目的為何?
ceh-m15-sql-q2 · 原創練習

使用者要選排序欄位,較適當作法是?

使用者要選排序欄位,較適當作法是?

連結下一個概念

詞彙:參數化查詢·授權

參考來源與範圍

以下來源支持技術原理;例子、題目與安全練習由本系列原創設計。