You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中参数化SQL表名且避免SQL注入安全漏洞

SQL参数仅支持传递查询值,无法用于替换表名、列名等SQL标识符,所以直接用@tableName作为表名占位符会抛出找不到表变量的异常。以下是两种支持任意合法表名、同时完全避免SQL注入的实现方案:

方案1:表名合法性校验 + QUOTENAME转义动态查询

核心逻辑是先校验传入的表名确实是当前数据库的合法表,再通过SQL Server内置的QUOTENAME函数将表名转义为安全标识符,再执行动态查询:

// 校验表名是否为当前数据库的合法表
private bool IsValidTableName(string tableName)
{
    const string checkSql = "SELECT COUNT(1) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName";
    using var command = new SqlCommand(checkSql, _connection);
    command.Parameters.AddWithValue("@TableName", tableName);
    return (int)command.ExecuteScalar() > 0;
}

private DataTable RetrieveEmptyDataTable(string tableName)
{
    if (!IsValidTableName(tableName))
    {
        throw new ArgumentException($"指定的表 {tableName} 不存在", nameof(tableName));
    }

    var table = new DataTable() { TableName = tableName };
    // 通过QUOTENAME转义表名构造安全的动态SQL
    const string querySql = @"
        DECLARE @Sql NVARCHAR(MAX) = 'SELECT TOP 0 * FROM ' + QUOTENAME(@TableName)
        EXEC sp_executesql @Sql
    ";
    using var command = new SqlCommand(querySql, _connection);
    command.Parameters.AddWithValue("@TableName", tableName);
    using SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
    dataAdapter.Fill(table);

    return table;
}

如果需要支持带Schema的表名(如dbo.User),可以拆分Schema和表名分别校验、分别用QUOTENAME包裹即可。

方案2:查询系统表手动构造DataTable

该方案完全避免拼接表名到业务查询语句,所有表名仅作为查询系统表的参数传递,彻底消除SQL注入风险,性能也更优:

private DataTable RetrieveEmptyDataTable(string tableName)
{
    const string columnQuery = @"
        SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, CHARACTER_MAXIMUM_LENGTH
        FROM INFORMATION_SCHEMA.COLUMNS 
        WHERE TABLE_NAME = @TableName
        ORDER BY ORDINAL_POSITION
    ";
    
    var table = new DataTable() { TableName = tableName };
    using var command = new SqlCommand(columnQuery, _connection);
    command.Parameters.AddWithValue("@TableName", tableName);
    using var reader = command.ExecuteReader();
    
    if (!reader.HasRows)
    {
        throw new ArgumentException($"指定的表 {tableName} 不存在", nameof(tableName));
    }

    while (reader.Read())
    {
        string columnName = reader.GetString(0);
        string sqlDataType = reader.GetString(1);
        bool allowDbNull = reader.GetString(2) == "YES";
        Type csharpType = MapSqlTypeToCSharpType(sqlDataType);
        
        var column = new DataColumn(columnName, csharpType)
        {
            AllowDBNull = allowDbNull
        };
        // 可按需补充列长度、主键、默认值等其他属性配置
        table.Columns.Add(column);
    }

    return table;
}

// SQL数据类型与C#类型映射,可根据业务需要补充全所有用到的类型
private Type MapSqlTypeToCSharpType(string sqlType)
{
    return sqlType.ToLower() switch
    {
        "int" => typeof(int),
        "bigint" => typeof(long),
        "varchar" or "nvarchar" or "text" or "ntext" => typeof(string),
        "datetime" or "datetime2" or "smalldatetime" => typeof(DateTime),
        "bit" => typeof(bool),
        "decimal" or "numeric" or "money" or "smallmoney" => typeof(decimal),
        "float" => typeof(double),
        "real" => typeof(float),
        "uniqueidentifier" => typeof(Guid),
        _ => throw new NotSupportedException($"暂不支持的SQL数据类型:{sqlType}")
    };
}

内容的提问来源于stack exchange,提问作者Nigel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 14:45:03