$sql = "SELECT * FROM test
WHERE username = '$username'
AND password = '$password'";
$res = mysql_query($sql);
if (mysql_num_rows($res)) {
header('Location: home.php');
}
| 輸入位置 | 惡意輸入 | 生成 SQL | 原理 |
|---|---|---|---|
| password | ***" OR 1=1 -- | ... AND password = "***" OR 1=1 --" | 恆真條件繞過驗證 |
| username | ***" UNION SELECT * FROM users -- | ... WHERE username = "***" UNION SELECT * FROM users --" | 聯合查詢讀取其他表 |
用戶輸入直接拼接進 SQL 字符串,未經轉義或參數化,導致數據與代碼邊界模糊。
// PDO 方式
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$stmt = $pdo->prepare('SELECT * FROM test WHERE username = ? AND password = ?');
$stmt->execute([$username, $password]);
if ($stmt->fetch()) { /* 登錄成功 */ }
// ThinkPHP / Laravel / Yii 等
$user = User::where('username', $username)
->where('password', $password) // 實際應存儲哈希
->first();
function clean_input($data) {
if (is_numeric($data)) return intval($data);
if (!get_magic_quotes_gpc()) $data = addslashes($data);
return $data;
}
$_GET = array_map('clean_input', $_GET);
$_POST = array_map('clean_input', $_POST);
缺點: 易漏過濾、編碼繞過、二次注入風險、不支持預處理性能優勢。
function post_check($post) {
if (!get_magic_quotes_gpc()) $post = addslashes($post);
$post = str_replace('_', '\\_', $post);
$post = str_replace('%', '\\%', $post);
$post = nl2br($post);
$post = htmlspecialchars($post);
return $post;
}
password_hash() + password_verify()Db::name('user')->where('username', $username)->find() 內部參數化prepare() + execute() 標準化SQL 注入本質是「數據未經處理進入代碼層」。參數化查詢 從根源分離代碼與數據,是唯一徹底解法。歷史項目若難重構,務必全局強制轉義並審計每個入口。