首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

防 SQL 注入:以程式碼產生參數化通用分頁查詢

     編輯:關於SqlServer

通用分頁預存程序雖方便,但因在程序內部拼接動態 SQL,極易遭 SQL 注入。單純過濾單引號(轉為雙引號)無法抵禦編碼繞過攻擊,參數化查詢才是根本解方。然而傳統通用分頁預存程序無法參數化,若為每個查詢單獨寫分頁程序又會大增維護成本。

解決方案:程式碼層產生參數化分頁 SQL

在應用程式層(C#)建立 PagerQuery 類別,封裝分頁參數(頁碼、頁面大小、主鍵、SELECT/FROM/WHERE/GROUP BY/ORDER BY 子句),由程式碼組裝成 參數化的 CTE 分頁查詢,再交由 ADO.NET 以參數方式執行,兼顧安全與重用。

核心程式碼結構

public class PagerQuery
{
    private int _pageIndex;
    private int _pageSize = 20;
    private string _pk;
    private string _fromClause;
    private string _groupClause;
    private string _selectClause;
    private string _sortClause;
    private StringBuilder _whereClause = new StringBuilder();

    // 屬性封裝各子句...
    public string PK { get; set; }
    public string SelectClause { get; set; }
    public string FromClause { get; set; }
    public StringBuilder WhereClause { get; set; }
    public string GroupClause { get; set; }
    public string SortClause { get; set; }
    public int PageIndex { get; set; }
    public int PageSize { get; set; }

    // 產生快取 Key
    public override string GetCacheKey() { ... }

    // 產生總筆數查詢
    public string GenerateCountSql() { ... }

    // 產生含總筆數的分頁查詢(使用 CTE + ROW_NUMBER)
    public string GenerateSqlIncludeTotalRecords() { ... }

    // 產生純分頁查詢
    public override string GenerateSql() { ... }
}

關鍵設計要點

  • WHERE 子句使用 StringBuilder 累加,呼叫端以 WhereClause.Append(" AND Col = @Param") 方式建立參數化條件,參數值再由 SqlParameter 集合傳遞。
  • 分頁邏輯採用 CTE + ROW_NUMBER() OVER (ORDER BY ...),相容 SQL Server 2005 以上版本,效能優於舊式 TOP 巢狀查詢。
  • 排序欄位預設為主鍵,避免未指定 ORDER BY 導致結果不穩定。
  • 快取 Key 包含所有查詢子句,方便搭配輸出快取或查詢計畫重用。

使用範例

var pager = new PagerQuery
{
    PageIndex = 2,
    PageSize = 20,
    PK = "OrderID",
    SelectClause = "OrderID, CustomerID, OrderDate",
    FromClause = "dbo.Orders",
    SortClause = "OrderDate DESC"
};
pager.WhereClause.Append(" AND CustomerID = @CustID");
// 後續建立 SqlCommand,指定 CommandText = pager.GenerateSql()
// 並加入 @CustID 參數執行

優勢總結

  • 徹底杜絕 SQL 注入:所有使用者輸入皆透過參數傳遞。
  • 保留通用性:同一個類別支援任意資料表、任意篩選條件的分頁需求。
  • 效能最佳化:CTE 分頁配合適當索引,執行計畫穩定可重用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved