應用程式未對使用者輸入進行驗證/過濾,直接拼接至 SQL 陳述式,導致攻擊者能注入任意 SQL 片段,竊取/篡改/刪除資料,甚至透過 xp_cmdshell 奪取作業系統控制權。
id=123 AND 1=1 正常 / id=123 AND 1=2 異常 → 存在注入。name=test' AND '1'='1 正常 / name=test' AND '1'='2 異常。WAITFOR DELAY '0:0:5' 或布林邏輯差異推斷。-- SQL Server 特徵
SELECT @@VERSION;
-- Oracle 特徵
SELECT * FROM v$version;
-- MySQL 特徵
SELECT VERSION();
sysadmin? SELECT IS_SRVROLEMEMBER('sysadmin')。xp_cmdshell 是否啟用? EXEC sp_configure 'xp_cmdshell'。| 技巧 | 範例 | 原理 |
|---|---|---|
| 大小寫混淆 | SeLeCt, UnIoN | VBScript/ASP 不區分大小寫,過濾器可能遺漏 |
| URL 編碼 | %27 (')、%20 (空白) | IIS 解碼後才交給應用,繞過字串比對 |
| Unicode/雙重編碼 | %u0027, %2527 | 利用解碼層次差異 |
| 註釋截斷 | ';--, ';/* | 截斷後續原始 SQL |
| 內聯註釋 | /**/SELECT/***/ | 繞過關鍵字過濾 |
-- C# ADO.NET
cmd.CommandText = "SELECT * FROM Users WHERE UserName = @u AND PwdHash = @p";
cmd.Parameters.AddWithValue("@u", userInput);
cmd.Parameters.AddWithValue("@p", pwdHash);
-- Java JDBC
PreparedStatement ps = conn.prepareStatement("SELECT * FROM Users WHERE UserName = ? AND PwdHash = ?");
ps.setString(1, userInput);
ps.setString(2, pwdHash);
-- PHP PDO
$stmt = $pdo->prepare("SELECT * FROM Users WHERE UserName = ? AND PwdHash = ?");
$stmt->execute([$userInput, $pwdHash]);
原理: SQL 碼與資料分離,資料庫引擎將參數視為字面值,永遠不會被解析為 SQL 指令。
CREATE PROC usp_GetUser @UserName NVARCHAR(50), @PwdHash NVARCHAR(128)
AS
SELECT * FROM Users WHERE UserName = @UserName AND PwdHash = @PwdHash;
⚠️ 嚴禁在預存程序內動態拼接 SQL 再 EXEC(@sql),除非對參數做嚴格白名單驗證。
Int32.TryParse、範圍檢查。customErrors="RemoteOnly"、PHP display_errors=Off)。xp_cmdshell 呼叫。EXEC(, sp_executesql, + @var + 等動態 SQL 模式。-- 關閉 xp_cmdshell(預設關閉)
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;
-- 啟用參數化強制(資料庫範圍,SQL 2008+)
ALTER DATABASE [MyDB] SET PARAMETERIZATION FORCED;
-- 限制登入失敗鎖定
ALTER LOGIN [WebAppUser] WITH CHECK_POLICY = ON;
SQL Injection 不是資料庫漏洞,是**應用層拼接字串的架構缺陷**。參數化查詢是唯一根治方案;其餘層級(驗證、最小權限、WAF、稽核)是縱深防禦的安全網。將「拼接 SQL」視為代碼審查的紅線,建立「參數化優先」的開發文化,才能從根本上消除這類風險。