近期社群討論「高效通用分頁預存程序帶有 SQL 注入漏洞」及「防注入:參數化通用分頁查詢」。筆者認為:預存程序本身不存在注入漏洞,漏洞源於應用層拼接 SQL 字串時未妥善處理參數。若有實際注入手法,請不吝指教。
建立 person 表(id、last_name、first_name),撰寫查詢預存程序 getPerson 接收 @strWhere 參數動態拼接:
CREATE PROC getPerson
@strWhere VARCHAR(100) = '' -- 查詢條件(勿含 WHERE 關鍵字)
AS
BEGIN
DECLARE @strSQL VARCHAR(1000);
SET @strSQL = 'SELECT TOP 10 * FROM person WHERE 1=1 ';
IF @strWhere != ''
SET @strSQL = @strSQL + @strWhere;
PRINT(@strSQL);
EXEC(@strSQL);
END
若應用層直接拼接使用者輸入:
-- 不安全寫法
strWhere += " AND first_name LIKE '%" + sUserName + "%'";
當 sUserName = "Jim's dog" 時,單引號閉合導致語法錯誤或被惡意利用。正確格式應為 AND first_name LIKE '%Jim''s dog%'(單引號轉義為雙引號)。
public string SafeRequest(string str) {
str = str.ToLower();
string SQL_KILL = "'|and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|set|;|from|=|--|drop|<|>";
foreach (string kw in SQL_KILL.Split('|')) {
if (str.IndexOf(kw) > -1) {
if (kw == "'") str = str.Replace("'", "''");
else str = str.Replace(kw, "");
}
}
return str;
}
// 使用
if (!string.IsNullOrEmpty(sUserName))
strWhere += " AND first_name LIKE '%" + SafeRequest(sUserName) + "%'";
另需注意十六進位編碼繞過過濾,建議同步檢查 HTML 編碼後的敏感字元。
Trim() 移除前後空格,破壞潛在注入語法DROP/TRUNCATE,注入成功亦難造成毀滅性後果結論:通用分頁預存程序本身無漏洞,漏洞源於應用層拼接不嚴謹。建議採用參數化查詢或 ORM 框架,從根源杜絕注入風險。