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

動態 SQL 防注入最佳實踐:參數化查詢 + DbParameter 集合模式

     編輯:關於SqlServer

SQL 注入根因與檢測

字符串拼接 SQL 是注入溫床。最簡單檢測:輸入框輸入 ' (單引號),若頁面拋出語法錯誤或異常頁面,**99% 存在注入漏洞**。

核心防禦原則:參數化查詢

  • SQL 代碼與數據分離:命令文本含佔位符 (`@Param` / `?`),數值通過參數集合傳遞,引擎編譯計劃時不再解析數據為代碼。
  • 支持多數據庫:佔位符風格由 `DbProviderFactory` / `DbHelper` 抽象層適配 (SQL Server `@p`、Oracle `:p`、MySQL/PostgreSQL `?`)。

企業級實現模式:動態條件 + 參數集合

public DataTable Search(string folderId, string searchValue, bool deleteMark)
{
    // 1. 固定條件轉換
    int deleteFlag = deleteMark ? 1 : 0;

    // 2. 基礎 SQL (使用常量定義表/列名,重構時編譯期發現變更)
    var sql = new StringBuilder();
    sql.Append(@"
SELECT  FieldId, FieldFolderId, FieldTitle, FieldFilePath, FieldFileSize,
        FieldReadCount, FieldDescription, FieldCategoryCode, FieldEnabled,
        FieldDeleteMark, FieldSortCode, FieldCreateUserId, FieldCreateUserRealname,
        FieldCreateDate, FieldModifyUserId, FieldModifyUserRealname, FieldModifyDate
FROM    " + CurrentTableName + @"
WHERE   FieldDeleteMark = @DeleteFlag");

    // 3. 安全可控的動態拼接 (folderId 為系統生成 GUID,非用戶輸入)
    var parameters = new List();
    parameters.Add(CreateParameter("@DeleteFlag", deleteFlag));

    if (!string.IsNullOrEmpty(folderId))
    {
        sql.Append(" AND FieldFolderId = @FolderId");
        parameters.Add(CreateParameter("@FolderId", folderId));
    }

    // 4. 用戶輸入全參數化 (多字段 LIKE 模糊查詢)
    if (!string.IsNullOrEmpty(searchValue))
    {
        searchValue = searchValue.Trim();
        string likePattern = searchValue.Contains("%") ? searchValue : "%" + searchValue + "%";

        sql.Append(@"
    AND (FieldTitle LIKE @Search
         OR FieldCreateUserRealname LIKE @Search
         OR FieldContents LIKE @Search
         OR FieldDescription LIKE @Search)");

        // 同一參數多處復用,僅添加一次
        parameters.Add(CreateParameter("@Search", likePattern));
    }

    // 5. 執行 (DbHelper 封裝多數據庫適配)
    return DbHelper.Fill(sql.ToString(), parameters.ToArray());
}

// 輔助:統一創建參數,隱藏 Provider 差異
private IDbDataParameter CreateParameter(string name, object value)
{
    var p = DbHelper.GetParameter(name);
    p.Value = value ?? DBNull.Value;
    return p;
}

代碼亮點解析

技術點收益
StringBuilder + 列表參數避免字符串拼接性能損耗,動態條件靈活組裝
常量定義表/列名重構友好,編譯期捕獲架構變更
同一參數多處復用減少參數數量,計劃緩存命中率高
LIKE 模式統一處理用戶輸入含 `%` 時保持原意,否則自動包裹
DeleteMark 替代 WHERE 1=1語義清晰,避免經典拼接陷阱
關鍵字大寫 + 縮進可讀性強,符合團隊規範
DbHelper 抽象層支持 SQL Server/Oracle/MySQL/PostgreSQL 無縫切換

常見反模式與修正

反模式風險修正
sql += " WHERE Name = '" + txtName.Text + "'"直接注入參數化 `@Name`
EXEC('SELECT * FROM ' + @TableName)標識符注入白名單驗證表名、或用 `QUOTENAME`
存儲過程內 `EXEC(@DynamicSQL)` 且拼接參數二次注入存儲過程內同樣參數化、或改用 `sp_executesql` + 參數
用 `REPLACE(@Input, '''', '''''')` 轉義繞過技巧多 (Unicode、編碼、二次解碼)拒絕手工轉義,唯一正解:參數化

進階防護:多層纏繞

  1. 輸入驗證:長度、格式、範圍、業務規則 (白名單正則)。
  2. 參數化查詢:核心防線,所有動態 SQL 無例外。
  3. 最小權限賬號:應用連接賬號僅擁有 `SELECT/INSERT/UPDATE/DELETE`,無 `DDL`/`EXECUTE`/`xp_cmdshell` 權限。
  4. WAF/IDS:網絡層攔截明顯攻擊載荷 (聯合查詢、延時、報錯注入特徵)。
  5. 審計日誌:記錄所有失敗登錄、DDL、大量錯誤查詢,配合 SIEM 告警。

總結

「參數化查詢 + 動態條件集合 + 抽象層適配」是防注入的**工程化標準解法**,兼顧安全、性能、可維護性與多數據庫兼容。拒絕任何形式的字符串拼接 SQL,將其作為代碼審查的紅線規則。

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