SQL参数化与使用string.format

时间:2019-02-22 15:41:58

标签: c# sql-server sql-injection sql-parametrized-query

就防御SQL注入而言,对于更简单的查询,以下策略之一是否比另一种更有效?:

  1. 使用参数化:

    using (SqlCommand command = new SqlCommand(@"SELECT * FROM @table", connection))
    {
        command.Parameters.AddWithValue("@table", table_name);
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                ...
            }
        }
    }
    
  2. 使用string.Format

    using (SqlCommand command = new SqlCommand(string.Format(@"SELECT * FROM {0}",table_name), connection))
    using (SqlDataReader reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            ...
        }
    }
    

3 个答案:

答案 0 :(得分:2)

我在评论中略微提及了这一点,但我也会在此处发布答案。

参数化(我认为)始终是解决问题的方法,因为它可以确保查询的“安全性”(注入参数化查询更加困难/不可能),并且还允许重复使用查询计划,也会很有好处。

但是,对于这里的内容,您无法按照您的期望参数化SQL。变量不能替换对象的名称(db<>fiddle)。为此,您需要动态SQL。

我不会假装我知道C#,但是我不知道您拥有什么,那意味着您有类似“某物”的查询:

using (SqlCommand command = new SqlCommand(@"DECLARE @SQL nvarchar(MAX) = N'SELECT * FROM ' + QUOTENAME(@table) + N';'; EXEC sp_executesql @SQL;", connection))
{
    command.Parameters.AddWithValue("@table", table_name);

老实说,我不知道这种方法是否可以在C#中工作,但这就是如何用(非常简单的方式)参数化动态对象。

答案 1 :(得分:1)

就SQL注入而言,参数化更安全。处理字符串和日期也更好。例如,如果您的字符串是这样的:

"I haven't sleep in two days"

如果尝试对查询进行String.Format格式化,则必须将'字符加倍,否则查询将失败。就像您将其参数化一样,SQL会自己完成。

我执行String.Format的唯一原因是,例如,当我有一个int列表并且想要执行“ WHERE COL IN()”条件时。在这种情况下,我将执行String.Format并在int上加入List,以在“ IN”子句中生成值。请注意,在这种情况下,我有一个int列表,因此这里没有SQL注入的机会。

我总是在动态SQL上使用String.Format,例如在您的示例中指定表名。

答案 2 :(得分:0)

始终使用参数化查询仅具有一个sql计划实例(仅出于最佳性能)。

参数化查询看起来像这样

select * from Table t where t.Id = @P1