SQL 注入是指攻擊者透過輸入精心構造的惡意字串,改變原本 SQL 語句的邏輯,進而竊取、竄改、刪除資料庫資料,甚至取得伺服器控制權。
' OR 1=1 --、'; DROP TABLE users; --。假設脆弱程式碼:
<?php
$conn = mysqli_connect("localhost", "root", "", "demo");
$name = $_POST['username'];
$pwd = $_POST['password'];
$sql = "SELECT * FROM users WHERE username='$name' AND password=MD5('$pwd')";
$res = mysqli_query($conn, $sql);
if (mysqli_num_rows($res) > 0) {
// 登入成功
}
?>
攻擊者在帳號欄輸入:admin' --,密碼隨意。
實際執行 SQL 變為:SELECT * FROM users WHERE username='admin' --' AND password=MD5('...'),-- 註解掉後續條件,直接以 admin 身分登入。
UNION SELECT 讀取其他資料表。SLEEP() 延遲判斷。DROP TABLE 等破壞性指令(視驅動支援度)。永遠不要用字串拼接組裝 SQL!
<?php
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username=? AND password=MD5(?)");
$stmt->bind_param("ss", $name, $pwd);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) { /* 登入成功 */ }
$stmt->close();
?>
<?php
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=:user AND password=MD5(:pwd)");
$stmt->execute([':user' => $name, ':pwd' => $pwd]);
if ($stmt->rowCount() > 0) { /* 登入成功 */ }
?>
display_errors,記錄至 log,避免洩露資料表結構。「用
addslashes()或mysql_real_escape_string()就安全了?」
錯。編碼繞過、字元集問題、二次注入等情況仍可突破。唯有參數化查詢才是根本解法。
總結:所有動態 SQL 必須使用預處理語句,搭配最小權限、錯誤隱藏、WAF,建立纵深防禦。