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

addslashes vs mysql_real_escape_string:SQL 注入防禦的正確姿勢

     編輯:PHP 相關知識

核心結論先行

新代碼請直接使用 PDO 預處理語句 (Prepared Statements),完全避免手動轉義。 本文僅針對存量代碼維護、歷史認知糾偏。

三個函數對比

函數轉義範圍字符集感知PHP 版本狀態
addslashes()單引號、雙引號、反斜杠、NUL❌ 無感知所有不推薦用於 SQL
mysql_escape_string()MySQL 特殊字符❌ 無感知PHP 4.3.0+已移除 (PHP 7.0)
mysql_real_escape_string()MySQL 特殊字符✅ 需活躍連接,讀取 character_set_clientPHP 4.3.0+已移除 (PHP 7.0)

為什麼 addslashes 防不住注入?

經典 GBK 編碼繞過漏洞:

<?php
// 假設連接字符集為 GBK
$input = chr(0xbf) . chr(0x27) . ' OR 1=1 /*'; // 0xbf27 是有效 GBK 字符 '縗' 的第二字節 + 單引號
// addslashes 將 0x27 轉為 0x5c27
$escaped = addslashes($input); // 0xbf 0x5c 0x27 ...
// MySQL 以 GBK 解析:0xbf5c 是一個合法字符 '鰈',0x27 依然是單引號 → 注入成功
?>
mysql_real_escape_string 知道當前連接是 GBK,會將 0xbf27 整體視為多字節字符,不插入反斜杠,從而避免產生新的合法字符組合。

mysql_real_escape_string vs mysql_escape_string

  • mysql_real_escape_string($str, $link):**必須傳入連接資源** (或使用最近打開的連接),讀取連接的字符集設置。
  • mysql_escape_string($str):無連接參數,假設默認字符集 (通常 latin1),**不安全**。

magic_quotes_gpc 歷史遺毒 (PHP 5.4 已移除)

<?php
// 舊代碼常見模式
if (!get_magic_quotes_gpc()) {
    $lastname = addslashes($_POST['lastname']);
} else {
    $lastname = $_POST['lastname']; // 已被自動 addslashes
}
// 問題:magic_quotes 也是 addslashes,同樣有 GBK 漏洞!
// 正確做法:無論 magic_quotes 狀態,統一用 mysql_real_escape_string 或預處理
?>

現代最佳實踐:PDO 預處理 (參數化查詢)

<?php
$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 = ? AND status = ?');
$stmt->execute([$email, $status]);
$user = $stmt->fetch();

// 優勢:
// 1. 數據與代碼徹底分離,零注入風險
// 2. 同一 SQL 重複執行只解析一次,性能更好
// 3. 自動處理類型轉換、NULL、字符集
?>

存量代碼遷移清單

  1. 全局搜索 addslashes( / mysql_real_escape_string( / mysql_escape_string(。
  2. 將動態拼接 SQL 重構為 PDO::prepare + execute([...])。
  3. 若暫時無法重構 (極其罕見):**強制設置連接字符集為 utf8mb4**,並使用 mysqli_real_escape_string($link, $str) (mysqli 版本仍保留)。
  4. 刪除所有 magic_quotes_gpc 相關判斷代碼。

總結

addslashes 是字符串級轉義,**不懂 SQL、不懂字符集**,僅適用於非數據庫場景 (如寫入文件、生成 JS 字符串)。mysql_real_escape_string 雖懂字符集,但屬於 **已棄用的 mysql_* 擴展**。**唯一正解:PDO 預處理 + 關閉模擬預處理**。

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