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

PHP 防止 SQL 注入的最佳實踐:預處理語句完整指南

     編輯:PHP 相關知識

SQL 注入仍是 Web 應用最常見的高危漏洞。根本對策只有一個——永遠使用預處理語句與參數化查詢,絕不拼接字串。本文以 PDO 與 mysqli 為例,示範正確用法與關鍵設定。

為什麼字串拼接會導致注入?

當使用者輸入 value'); DROP TABLE users;-- 並直接拼接進 SQL:

$sql = "INSERT INTO log (msg) VALUES ('" . $_POST['msg'] . "')";
// 實際執行變成:
// INSERT INTO log (msg) VALUES ('value'); DROP TABLE users;--')

資料庫會執行兩條語句,造成災難性後果。

方案一:PDO(推薦,支援多種資料庫)

<?php
// 1. 建立連線並關鍵:關閉模擬預處理
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // 必須!使用真正預處理
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// 2. 準備語句(命名佔位符)
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute([':email' => $userInput]);

// 3. 取得結果
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    // 處理資料
}

方案二:mysqli(原生 MySQL 擴充)

<?php
$mysqli = new mysqli('127.0.0.1', 'user', 'pass', 'test');
$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ?');
$stmt->bind_param('s', $userInput); // 's' 表字串,'i' 整數, 'd' 雙精度, 'b' Blob
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) { /* ... */ }

核心原理:為何這能防注入?

  1. 解析與資料分離:SQL 模板先送資料庫編譯,參數稍後以二進位協定傳送,資料庫絕不會將參數視為 SQL 片段。
  2. 型別安全:bind_param 強制指定型別,進一步消除注入面。
  3. 效能加分:同一連線重複執行同樣預處理語句,資料庫只解析一次。

常見誤區提醒

  • ❌ PDO::quote() 或 mysqli_real_escape_string() 仍屬「過濾法」,無法覆蓋所有邊緣情況(如字元集陷阱)。
  • ❌ 將預處理用於資料表/欄位名稱——識別子無法參數化,需經白名單驗證。
  • ✅ PHP < 5.3.6 無法在 DSN 設定 charset,請升級或執行 SET NAMES utf8。

結論:全專案統一使用預處理語句,是唯一可靠、可維護的防注入基線。

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