$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
輸入:username: admin' --、password: 任意
實際執行:SELECT * FROM users WHERE username = 'admin' --' AND password = 'xxx' → 註解掉密碼驗證。
$sql = "SELECT * FROM users WHERE id = $id";
輸入:id: 1 UNION SELECT * FROM users
$sql = "SELECT * FROM goods WHERE name LIKE '%$keyword%'";
輸入:% → 回傳全表。
INSERT INTO users(username, password, grade) VALUES('$user', '$pass', '1');
輸入密碼:123', '9')/* → 竄改 grade 為 9。
| 層級 | 方案 | 優缺點 |
|---|---|---|
| 1️⃣ | php.ini: magic_quotes_gpc = On | 已棄用,PHP 5.4+ 移除,易被 char() 繞過 |
| 2️⃣ | 查詢後應用層比對密碼 | 需額外查詢,仍有二次注入風險 |
| 3️⃣ | PDO 預處理(推薦) | 參數化查詢,SQL 與資料分離,根治注入 |
| 4️⃣ | WAF/IDS 入侵檢測 | 網路層攔截,規則維護成本高,作為纵深防禦 |
$dsn = "mysql:host=localhost;port=3306;dbname=test;charset=utf8";
$pdo = new PDO($dsn, 'root', '123456');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT * FROM users WHERE username = ? AND password = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$username, $password]);
$user = $stmt->fetch();
if (!$user) {
die('登入失敗');
}
ERRMODE_EXCEPTION 讓錯誤可被 try-catch 捕獲。SELECT/INSERT/UPDATE/DELETE。UNION SELECT、SLEEP() 等特徵。