字符串拼接 SQL 是注入溫床。最簡單檢測:輸入框輸入 ' (單引號),若頁面拋出語法錯誤或異常頁面,**99% 存在注入漏洞**。
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、編碼、二次解碼) | 拒絕手工轉義,唯一正解:參數化 |
「參數化查詢 + 動態條件集合 + 抽象層適配」是防注入的**工程化標準解法**,兼顧安全、性能、可維護性與多數據庫兼容。拒絕任何形式的字符串拼接 SQL,將其作為代碼審查的紅線規則。