Параметризация SQL против использования string.format
С точки зрения защиты от внедрения SQL для более простых запросов, является ли одна из приведенных ниже стратегий более эффективной, чем другая?
Использование параметризации:
using (SqlCommand command = new SqlCommand(@"SELECT * FROM @table", connection)) { command.Parameters.AddWithValue("@table", table_name); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { ... } } }
С помощью
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