Как избежать простых SQL-запросов в С# для SqlServer
Я использую API, который ожидает строку SQL. Я беру ввод пользователя, убегаю и передаю его в API. Вход пользователя довольно прост. Он запрашивает значения столбцов. Например:
string name = userInput.Value;
Затем я создаю SQL-запрос:
string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
name.replace("'", "''"));
Насколько это достаточно безопасно? Если это не так, существует ли простая функция библиотеки, которая делает безопасные значения столбца:
string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
SqlSafeColumnValue(name));
API использует SQLServer в качестве базы данных.
Ответы
Ответ 1
Поскольку использование SqlParameter не является опцией, просто замените 'with' '(две одинарные кавычки, а не одну двойную кавычку) в строковых литералах. Что это.
К потенциальным downvoters: перечитайте первую строку вопроса. "Использовать параметры" также была моя реакция кишки.
EDIT: да, я знаю об атаках SQL-инъекций. Если вы считаете, что это цитирование уязвимо для них, предоставьте рабочий контрпример. Я думаю, что нет.
Ответ 2
Простой:
const string sql = "SELECT * FROM SOME_TABLE WHERE Name = @name";
и добавьте параметр @name
со значением:
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@name", name);
Ответ 3
Я использовал динамический sql (я могу услышать, как расстрельная команда загружает свои винтовки) для функции поиска, но она будет ломаться всякий раз, когда пользователь будет искать кого-то с фамилией типа "O'Reilly".
Мне удалось разобраться в работе (прочитайте "hack" ):
Создал скалярнозначную функцию в sql, которая заменила одну кавычку двумя одинарными кавычками, эффективно избегая оскорбительной одинарной кавычки, так что "... Фамилия LIKE '% O'Reilly%' AND..."
становится "... Фамилия LIKE '% O''Reilly%' AND..."
Эта функция вызывается изнутри sql всякий раз, когда я подозреваю, что поля могут содержать один символ кавычки, то есть: firstname, lastname.
CREATE FUNCTION [dbo].[fnEscapeSingleQuote]
(@StringToCheck NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @Result NVARCHAR(MAX)
SELECT @Result = REPLACE(@StringToCheck, CHAR(39), CHAR(39) + CHAR(39))
RETURN @Result
END
Не очень элегантный или эффективный, но он работает, когда вы в порядке.
Ответ 4
Возможно, вы захотите заменить "на" вместо "параметрирования", когда нужно в течение короткого времени решить проблему в большом количестве ad hoc sql с минимальным риском поломки и минимальным тестированием.
Ответ 5
Лучше всего использовать sql-параметры, но тогда у вас есть ограничение на 2300 параметров для запроса. В большинстве случаев этого будет более чем достаточно. Но в редких случаях, когда вы превышаете это ограничение, я вижу это как вариант.
Ответ 6
SqlCommand и Entity Framework используют exec sp_executesql...
.
Таким образом, действительно существует альтернатива исходным строкам с вашим собственным шаблоном экранирования. С SqlCommand вы технически используете параметризованные запросы, но вы обходите абстракцию ADO.Net базового кода SQL.
Таким образом, хотя ваш код не предотвращает SQL Injection, конечным ответом является sp_executesql, а не SqlCommand.
Сказав это, я уверен, что существуют особые требования к обработке для создания строки, содержащей SQL Injection, которая использует sp_executesql.
см.: Как вернуть значения из динамической хранимой процедуры SQL в платформу Entity Framework?
Ответ 7
Если вам нужно избежать строки для запроса MSSQL, попробуйте следующее:
System.Security.SecurityElement.Escape(Value)