延續前兩篇關於 SQL 注入攻擊的討論,本文將深入探討如何從根本上解決資料庫輸入安全問題。前文提到資料庫自帶的字符串過濾功能(如 mysql_real_escape_string)並非所有資料庫都支援,且 Base64 編碼雖能繞過特殊字符,但會增加 33% 儲存空間,且導致 PostgreSQL 無法使用 LIKE 查詢。顯然,單靠資料庫層面的轉義並不足夠。
預處理語句是目前公認最有效的防禦手段。其原理是將 SQL 查詢的結構與數據分離:先定義查詢模板(含佔位符),再綁定參數執行。資料庫引擎會預先編譯 SQL 結構,執行時僅填入數據,徹底杜絕了注入可能。
// 1. 定義預處理語句,指定參數類型為 text
pg_query($conn, "PREPARE stmt_name (text) AS SELECT * FROM users WHERE name=$1");
// 2. 執行並傳入實際參數
pg_query($conn, "EXECUTE stmt_name ({$name})");
// 3. 釋放預處理語句資源
pg_query($conn, "DEALLOCATE stmt_name");
上例中,$1 為佔位符,除此以外的所有字符均為固定結構,不可更改。這種「模板+參數」模式確保了用戶輸入永遠不會被解釋為 SQL 指令。
在 PHP 中,推薦使用 PDO 或 mysqli 的預處理介面,而非舊式 mysql_* 函數。例如:
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute(['name' => $name]);
$result = $stmt->fetchAll();
雖然早期 PHP 開發者常依賴 magic_quotes_gpc、addslashes 或資料庫專用轉義函數,但這些方法皆存在覆蓋面不全、重複轉義、編碼問題等缺陷。預處理語句從架構層面解決了 SQL 注入,應作為現代 PHP 開發的標準配置。下一篇將探討更多進階防禦技巧與實戰案例。