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

Sonar扫描提示C#代码存在SQL注入安全热点,该如何处理?

处理SQL注入安全热点的方案

问题根源

这段代码用string.Format直接拼接表名和主键列名到SQL语句中,尽管这两个值来自实体类型的元数据,但Sonar无法确认GetTableName和GetPrimaryKeyName是否会返回不可信内容,因此标记为安全热点。

解决方法

1. 严格验证并转义标识符

给动态获取的表名、列名添加合法性校验,同时按照数据库规则转义标识符,避免恶意内容注入:

Type entryEntityType = entry.Entity.GetType();
string tableName = GetTableName(entryEntityType);
string primaryKeyName = GetPrimaryKeyName(entryEntityType);

// 验证标识符格式:只允许字母、数字、下划线
if (!IsValidDbIdentifier(tableName) || !IsValidDbIdentifier(primaryKeyName))
{
    throw new ArgumentException("非法的表名或主键列名");
}

// 转义标识符(SQL Server用[]包裹,MySQL用`,Oracle用"",根据数据库调整)
string escapedTableName = $"[{tableName}]";
string escapedPrimaryKey = $"[{primaryKeyName}]";

string deleteQuery = $"UPDATE {escapedTableName} SET IsDeleted = 1 WHERE {escapedPrimaryKey} = @id";          
Database.ExecuteSqlCommand(deleteQuery, new SqlParameter("@id", entry.OriginalValues[primaryKeyName]));

// 辅助校验方法
private bool IsValidDbIdentifier(string name)
{
    return !string.IsNullOrEmpty(name) && System.Text.RegularExpressions.Regex.IsMatch(name, @"^[a-zA-Z0-9_]+$");
}

2. 改用ORM内置软删除功能(推荐)

如果使用Entity Framework,可以直接通过ORM机制实现软删除,完全避免手写SQL的风险:

// 定义软删除接口
public interface ISoftDelete
{
    bool IsDeleted { get; set; }
}

// 实体类实现接口
public class YourEntity : ISoftDelete
{
    public int Id { get; set; }
    public bool IsDeleted { get; set; }
    // 其他业务属性
}

// 在DbContext中配置全局筛选与自动软删除
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 全局过滤已删除数据
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        if (typeof(ISoftDelete).IsAssignableFrom(entityType.ClrType))
        {
            modelBuilder.Entity(entityType.ClrType)
                .HasQueryFilter(e => EF.Property<bool>(e, "IsDeleted") == false);
        }
    }
}

public override int SaveChanges()
{
    // 将删除操作转为软删除
    foreach (var entry in ChangeTracker.Entries<ISoftDelete>())
    {
        if (entry.State == EntityState.Deleted)
        {
            entry.State = EntityState.Modified;
            entry.Entity.IsDeleted = true;
        }
    }
    return base.SaveChanges();
}

3. 封装为安全的存储过程

如果必须保留动态SQL逻辑,可将逻辑封装到存储过程中,在存储过程内做标识符白名单校验:

CREATE PROCEDURE SoftDeleteEntity
    @TableName NVARCHAR(128),
    @PrimaryKeyName NVARCHAR(128),
    @Id INT
AS
BEGIN
    -- 白名单校验:只允许预定义的合法表名和列名
    IF @TableName NOT IN ('User', 'Order', 'Product') 
        OR @PrimaryKeyName NOT IN ('Id', 'UserId', 'OrderId')
    BEGIN
        THROW 50000, "非法的表名或主键列名", 1;
    END

    DECLARE @Sql NVARCHAR(MAX) = N'UPDATE ' + QUOTENAME(@TableName) 
        + N' SET IsDeleted = 1 WHERE ' + QUOTENAME(@PrimaryKeyName) + N' = @Id'
    EXEC sp_executesql @Sql, N'@Id INT', @Id
END

C#调用代码:

Database.ExecuteSqlCommand("EXEC SoftDeleteEntity @TableName, @PrimaryKeyName, @Id",
    new SqlParameter("@TableName", tableName),
    new SqlParameter("@PrimaryKeyName", primaryKeyName),
    new SqlParameter("@Id", entry.OriginalValues[primaryKeyName]));

核心原则

  • 绝对禁止直接将用户输入作为表名/列名拼接SQL
  • 动态标识符必须经过合法性校验+数据库规则转义
  • 优先依赖ORM内置能力,减少手写SQL的安全风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:21:23