首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 防止 SQL 注入:從字串過濾到預處理語句的正確演進

     編輯:PHP 相關知識

為什麼單純的字串過濾不夠用?

早期 PHP 開發常見使用 str_replace()、preg_replace() 或自訂函數過濾「危險字符」(如單引號、分號、關鍵字 union、select 等)來防禦 SQL 注入。但這種「黑名單」策略存在根本缺陷:

  • 繞過技巧層出不窮:大小寫混淆、編碼繞過(URL encode、Unicode)、註釋截斷等。
  • 誤傷合法資料:使用者輸入包含 "O'Reilly"、"select * from" 等正常內容會被錯誤截斷。
  • 維護成本高:需持續更新關鍵字庫,且無法覆蓋所有資料庫方言差異。

現代 PHP 防注入黃金標準:預處理語句

PDO(PHP Data Objects)與 MySQLi 皆支援預處理語句,將 SQL 邏輯與資料分離,從根本上杜絕注入風險。

PDO 範例(推薦)

$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', $user, $pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false, // 關鍵:使用真正的預處理
]);

$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');
$stmt->execute(['email' => $email, 'status' => 1]);
$user = $stmt->fetch();

MySQLi 範例

$mysqli = new mysqli('localhost', $user, $pass, 'test');
$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ? AND status = ?');
$stmt->bind_param('si', $email, $status);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();

輔助防禦層:輸入驗證與最小權限

雖然預處理語句已解決注入核心問題,但纏合以下措施可構建纏深防禦:

  1. 輸入驗證:使用 filter_var()、ctype_*() 或正則表達式驗證格式(Email、電話、身分證字號等)。
  2. 型別轉換:整數欄位用 (int)$_GET['id'] 或 filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT)。
  3. 資料庫最小權限:應用程式帳號僅授予必要的 SELECT/INSERT/UPDATE/DELETE 權限,禁止 DROP、ALTER、GRANT 等管理操作。
  4. 錯誤訊息不外洩:生產環境關閉 display_errors,記錄錯誤至日誌供開發者排查。

歷史遺留代碼改造建議

若專案仍大量使用 mysql_* 與手動過濾函數:

  1. 優先改寫核心業務邏輯(登入、付費、個資查詢)為 PDO 預處理。
  2. 建立資料庫存取層,封裝通用 CRUD 方法,統一使用預處理。
  3. 逐步淘汰 magic_quotes_gpc、addslashes()、自訂 safe_replace() 等舊式過濾函數。
  4. 引入靜態分析工具掃描潛在注入點。

結語

字串過濾只能作為輔助手段,預處理語句才是防止 SQL 注入的唯一正解。現代 PHP 專案應以 PDO + 真實預處理為基礎,配合嚴格的輸入驗證與最小權限原則,構建穩健的資料庫安全防線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved