在动态代码中防止 sql 注入

Prevent sql injection in dynamic code

我需要使用来自 C# 代码的 sql 查询执行动态字符串并防止 sql 注入。

我的代码是这样的:

internal static string Get_Running_Cars(string from, string to)
        {
            return string.Format(
                 " declare @from as datetime = '{0}'" +
                 " declare @to as datetime = '{1}'" +
                 " select  top 3 DATEDIFF(second,starttime,endtime) as sum,carname as name" +
                 " from cars" +
                 " where @from < starttime and @to > endtime ", from, to
                 );
        }

在该代码中,我可以将恶意代码插入到这些字符串中。

如何安全使用它? 我应该阻止那些字符:';, -?

如果你愿意,可以称之为新手方法,但是尝试将输入事先解析为 DateTime 格式怎么样?

DateTime.TryParse()

    internal static string Get_Running_Cars(string from, string to)
    {
        DateTime test1, test2;
        if (!DateTime.TryParse(from, out test1) || !DateTime.TryParse(to, out test2))
            return null;
        //else is optional here, to show logic
        return string.Format(
             " declare @from as datetime = '{0}'" +
             " declare @to as datetime = '{1}'" +
             " select  top 3 DATEDIFF(second,starttime,endtime) as sum,carname as name" +
             " from cars" +
             " where @from < starttime and @to > endtime ", from, to
             );
    }

正确、更简单、更快并且更安全的方法是使用参数化查询。假设您使用 ADO.NET,您可以使用以下方法创建参数化查询:

public SqlCommand BuildCarsCommand(DateTime from,DateTime to)
{
    var sql= "select  top 3 DATEDIFF(second,starttime,endtime) as sum,carname as name" +
         " from cars where @from < starttime and @to > endtime ";
    var cmd=new SqlCommand(sql);
    cmd.Paramerers.AddWithValue("@from",from);
    cmd.Parameters.AddWithValue("@to", to);

    return cmd;
}

可以用SqlCommand.ExecuteReader

执行命令

使用Dapper,更简单。单行会传参数:

 IEnumerable<Car> cars=connection.Query<Car>(sql,new {From=@from, To=@to});

这将在内部创建一个 SqlCommand,传递参数,执行查询并将结果映射到汽车。

Entity Framework 并且大多数 ORM 也允许您 运行 参数化查询。

如果不是其中之一,您必须指定使用的数据访问方法。

在Entity Framework中你可以使用LINQ来获取这个查询,使用SqlFunctions.DateDiff来计算日期差异:

var cars=from car in myDbContext.Cars
         where car.starttime >  from and car.endtime < to
         select new {
                      sum=SqlFunction.DateDiff("second", car.starttime,car.endtime),
                      name=carname
                     }

我使用 EF,因此最好的答案是使用 'SqlParameter'。

我构建了这个对象:

public class SqlQueryEntity
    {
        public string query { get; set; }
        public object[] _params { get; set; }
    } 

并使用 DbRawSqlQuery 发送它。

我需要使用 'object' 数组插入查询,其中包含:

new SqlParameter[] { 
                    new SqlParameter("from", from),
                    new SqlParameter("to", to)
                }

'to' 和 'from' 可以包含 Datetime 对象。