Как избежать простых 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)