當用戶輸入直接拼接進 SQL 語句時,惡意輸入可改變查詢邏輯:
⚠ 警告: mysql_* 系列函數已在 PHP 7.0 移除,僅供歷史代碼維護參考。
string mysql_real_escape_string(string $string, resource $connection = null)
轉義特殊字符:\x00 \n \r \ ' " \x1a
核心優勢: SQL 邏輯與數據分離,從根源杜絕注入,支援多種數據庫。
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 使用真實預處理
];
$pdo = new PDO($dsn, 'username', 'password', $options);
prepare("SELECT * FROM users WHERE user = :user AND password = :pwd");
$stmt->execute(['user' => $user, 'pwd' => $pwd]);
$result = $stmt->fetchAll();
// 問號佔位符
$stmt = $pdo->prepare("SELECT * FROM users WHERE user = ? AND password = ?");
$stmt->execute([$user, $pwd]);
prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->execute(['name' => '張三', 'email' => 'zhangsan@example.com']);
$lastId = $pdo->lastInsertId();
// 更新
$stmt = $pdo->prepare("UPDATE users SET email = :email WHERE id = :id");
$stmt->execute(['email' => 'new@test.com', 'id' => 1]);
// 刪除
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
$stmt->execute(['id' => 1]);
prepare("SELECT * FROM users WHERE user = ? AND password = ?");
$stmt->bind_param('ss', $user, $pwd); // 'ss' 表示兩個字符串參數
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// 處理結果
}
$stmt->close();
| 層級 | 措施 | 說明 |
|---|---|---|
| 1. 代碼層 | 預處理語句 | 根本解決,PDO/MySQLi |
| 2. 數據庫層 | 最小權限原則 | Web 用戶僅擁有必要增刪改查權限,無 DROP/ALTER 權限 |
| 3. 應用層 | 輸入驗證與過濾 | 白名單驗證、長度限制、類型檢查 |
| 4. 監控層 | WAF / 日誌審計 | 異常 SQL 模式告警、慢查詢分析 |
| 5. 錯誤處理 | 不暴露 SQL 細節 | 生產環境關閉詳細錯誤輸出,記錄日誌而非顯示用戶 |
❌ 錯誤: addslashes() 能防注入 → 無效,不處理多字節字符編碼問題
❌ 錯誤: 過濾關鍵字(select, union 等) → 繞過極易,影響正常業務
❌ 錯誤: 只有數字才用預處理 → 所有外部輸入 都應使用預處理
✅ 正確: 統一使用 PDO 預處理 + 參數綁定,無例外
mysql_query、mysql_real_escape_string