首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

通用分頁預存程序的 SQL 注入漏洞深度剖析

     編輯:ASP.NET 基礎

廣為流傳的「萬能分頁預存程序」雖使用參數化輸入,但因內部動態拼接 SQL 字串再 `EXEC` 執行,導致單引號轉義失效,存在嚴重 SQL 注入風險,且無法在預存程序內修補。

漏洞預存程序核心邏輯

CREATE PROCEDURE Pagination
    @tblName varchar(255), @strGetFields varchar(1000) = '*',
    @fldName varchar(255) = '', @PageSize int = 10, @PageIndex int = 1,
    @doCount bit = 0, @OrderType bit = 0, @strWhere varchar(1500) = ''
AS
DECLARE @strSQL varchar(5000)
-- ... 根據參數拼接 @strSQL ...
-- 第一頁範例:
SET @strSQL = 'SELECT TOP ' + @PageSize + ' ' + @strGetFields + 
              ' FROM [' + @tblName + '] WHERE ' + @strWhere + ' ' + @strOrder
EXEC (@strSQL)

注入演示

假設呼叫端使用 `SqlParameter` 傳遞 `@strWhere`,輸入 `UserName LIKE '%Jim'' dog%'`,參數化後單引號變雙引號:

@strWhere = 'UserName LIKE ''%Jim'''' dog%'''

拼接後的動態 SQL:

SELECT TOP 20 * FROM [UserAccount] WHERE UserName LIKE '%Jim'' dog%' ORDER BY ID DESC

實際執行時,`LIKE '%Jim'` 後面的 ` dog%'` 被截斷。若攻擊者輸入 `Jim'; DELETE FROM UserAccount;--`,經雙引號轉義後仍能在 `EXEC` 時構成多語句攻擊。

為何參數化無效?

  • `SqlParameter` 只能參數化值,無法參數化表名、欄位名、WHERE 子句片段。
  • 預存程序內部將參數視為普通字串拼接,失去參數化保護邊界。

解決路徑

  1. 捨棄通用預存程序,改由資料存取層 (DAL) 組裝參數化 SQL,再呼叫 `sp_executesql` 或直接執行參數化命令。
  2. 若必須用預存程序,僅傳遞值參數,WHERE 條件結構固化在預存程序內,動態部分僅限值。
  3. 採用 ORM (Entity Framework/Dapper) 或 參數化內聯 SQL,完全避免字串拼接。

安全版 DAL 範例

public DataTable GetPaged(string table, string fields, string where, string order, 
                          int page, int size, out int total, params SqlParameter[] pars) {
    // 1. 計算總數
    string cntSql = $"SELECT COUNT(*) FROM {table} WHERE 1=1 {where}";
    total = (int)SqlHelper.ExecuteScalar(cntSql, pars);
    
    // 2. 分頁查詢 (SQL Server 2012+ OFFSET/FETCH)
    string sql = $@"
        SELECT {fields} FROM {table} 
        WHERE 1=1 {where} 
        ORDER BY {order} 
        OFFSET @offset ROWS FETCH NEXT @size ROWS ONLY";
    
    var list = new List(pars) {
        new SqlParameter("@offset", (page-1)*size),
        new SqlParameter("@size", size)
    };
    return SqlHelper.ExecuteDataTable(sql, list.ToArray());
}

呼叫端:`GetPaged("Users", "*", " AND UserName LIKE @kw", "Id DESC", 1, 20, out total, new SqlParameter("@kw", "%Jim%"))`

結論

「通用分頁預存程序」屬反模式,動態 SQL 拼接 + EXEC = 注入溫床。現代開發應回歸參數化查詢組裝於應用層,利用資料庫新版分頁語法 (OFFSET/FETCH, ROW_NUMBER) 獲得效能與安全雙贏。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved