Параметризация SQL против использования string.format

С точки зрения защиты от внедрения 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 ответа

Решение

Параметризация безопаснее с точки зрения внедрения SQL. Это также лучше для обработки строк и дат. Например, если ваша строка такая:

"I haven't sleep in two days"

Если вы попытаетесь использовать String.Format в своем запросе, вам придется удвоить символ ', иначе ваш запрос потерпит неудачу. Как будто вы его параметризовали, SQL сделает это сам.

Единственная причина, по которой я выполняю String.Format, - это когда у меня есть, например, список int и я хочу выполнить условие "WHERE COL IN () ". В этом случае я сделаю String.Format и присоединюсь к List в int, чтобы сгенерировать значения внутри предложения IN. Обратите внимание, что в этом случае у меня есть список int, поэтому здесь нет шансов на внедрение SQL.

Я всегда когда-нибудь использую String.Format для динамического SQL, например, для указания имени таблицы, как в вашем примере.

Я немного затронул это в своих комментариях, но здесь также выложу ответ.

Параметризация (на мой взгляд) - это всегда путь, так как он обеспечивает "безопасность" вашего запроса (его гораздо сложнее / невозможно ввести в параметризованный запрос), а также позволяет повторно использовать планы запросов, которые также могут быть большой пользы

Однако для того, что у вас есть, вы не можете параметризовать свой 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# таким образом, но именно так вы бы параметризовали динамический объект в (очень) простых терминах.

Всегда используйте параметризованные запросы, чтобы иметь только один экземпляр плана SQL (только для лучшей производительности).

Параметризованные запросы выглядят так

select * from Table t where t.Id = @P1
Другие вопросы по тегам