SQL 注入 是攻擊者通過構造惡意輸入,改變原本 SQL 語句的語義,從而竊取、篡改、刪除數據庫數據,甚至獲取服務器控制權的攻擊手段。它是 Web 應用中最危險、最普遍的漏洞之一。
<?php
$name = $_POST['username'];
$pwd = $_POST['password'];
$sql = "SELECT * FROM users WHERE username='$name' AND password=MD5('$pwd')";
$query = mysql_query($sql);
if (mysql_fetch_array($query)) {
header('Location: admin.php');
} else {
echo '登錄失敗';
}
用戶名輸入:' OR 1=1 #
密碼任意輸入。
SELECT * FROM users WHERE username='' OR 1=1 #' AND password=MD5('xxx')
' 閉合前面的單引號。OR 1=1 恆為真,導致 WHERE 條件永遠滿足。# 註釋掉後續所有內容(MySQL 中 # 為行註釋)。SELECT * FROM users,返回第一行記錄(通常是管理員),登錄成功。數據與代碼分離,數據庫驅動層負責轉義,徹底杜絕注入。
<?php
// PDO 示例
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=? AND password=MD5(?)");
$stmt->execute([$_POST['username'], $_POST['password']]);
$user = $stmt->fetch();
現代框架(Laravel Eloquent、ThinkPHP Db、Yii ActiveRecord)底層均使用參數化,正常使用安全。
User::where('username', $name)->where('password', md5($pwd))->first();
對預期為數字、枚舉、郵箱等的字段,嚴格校驗格式,拒絕非預期字符。
Web 應用數據庫賬號僅授予必要表的 SELECT/INSERT/UPDATE/DELETE,禁止 DROP、CREATE、FILE 等高危權限。
生產環境關閉 display_errors,記錄日志不顯示用戶,避免報錯回顯洩露表結構。
| 類型 | 特徵 | 示例載荷 |
|---|---|---|
| 聯合查詢注入 | 利用 UNION 合併結果集 | ' UNION SELECT 1,username,password FROM admin # |
| 報錯注入 | 利用數據庫報錯回顯數據 | ' AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT @@version))) # |
| 布爾盲注 | 頁面無回顯,通過真/假邏輯判斷 | ' AND (SELECT SUBSTRING(password,1,1) FROM admin)='a' # |
| 時間盲注 | 利用 SLEEP/BENCHMARK 延遲判斷 | ' AND IF(1=1, SLEEP(3), 0) # |
| 二次注入 | 惡意數據存儲後,二次使用時觸發 | 註冊用戶名 admin'--,後續修改密碼時注入 |
DB::listen、ThinkPHP Db::listen 可記錄慢/異常 SQL。SQL 注入的根源是**數據與代碼未分離**。堅持使用參數化查詢、ORM、嚴格輸入驗證、最小權限、隱藏錯誤信息,可構建強有力的防禦體系。安全無絕對,持續代碼審計、漏洞掃描、應急預案缺一不可。