Как параметризованные запросы помогают против внедрения SQL? - PullRequest
47 голосов
/ 29 марта 2011

В обоих запросах 1 и 2 текст из текстового поля вставляется в базу данных. Какое значение здесь имеет параметризованный запрос?

  1. Передача txtTagNumber в качестве параметра запроса

    SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(@TagNbr);" , conn);
    cmd.Parameters.Add("@TagNbr", SqlDbType.Int);
    cmd.Parameters["@TagNbr"].Value = txtTagNumber.Text;
    
  2. Преобразование txtTagNumber в целое число перед построением запроса

    int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */
    INSERT into Cars values(tagnumber.Text); /* then is it the same? */
    

Кроме того, здесь я бы использовал проверку Регулярного выражения, чтобы остановить вставку недопустимых символов.

Ответы [ 6 ]

44 голосов
/ 29 марта 2011

Параметризованные запросы выполняют правильную подстановку аргументов перед выполнением SQL-запроса. Это полностью исключает возможность «грязного» ввода, меняющего смысл вашего запроса. То есть, если вход содержит SQL, он не может стать частью того, что выполняется, потому что SQL никогда не вставляется в результирующий оператор.

16 голосов
/ 29 марта 2011

SQL-инъекция происходит, когда возможный параметр имеет sql внутри него, и строки не обрабатываются, как должно быть

например:

var sqlquerywithoutcommand = "select * from mytable where rowname =  '" + condition+''";

, а условие - строка, полученная изПользователь в запросе.Если условие является вредоносным, скажем, например:

var sqlquerywithoutcommand = "select * from mytable where rowname =  '" + "a' ;drop table  mytable where '1=1"+"'";

, вы можете в конечном итоге запустить вредоносные сценарии.

, но с использованием параметров ввод будет очищен от любых символов, которые могут содержать строковые символы ...

вы можете быть уверены, что независимо от того, что входит в него, вы не сможете запускать сценарии внедрения.

использование объекта команды с параметрами, которые фактически выполняются sql, будет выглядеть так

select * from mytable where rowname = 'a'';drop table mytable where 1=1'''

в сущности, он будет искать строку с rowname = a '; удалить таблицу mytable где 1 = 1' и не запускать оставшийся скрипт

10 голосов
/ 21 декабря 2016

Представьте себе динамический SQL-запрос

sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND
Pass=' + password

, поэтому простая инъекция sql будет состоять в том, чтобы просто ввести имя пользователя как ' OR 1=1--. Это фактически сделает запрос sql:

* 1007.*

Это говорит, что выберите всех клиентов, где их имя пользователя пусто ('') или 1 = 1, что является логическим значением, равным true.Затем он использует -, чтобы закомментировать оставшуюся часть запроса.Так что это будет просто распечатывать всю таблицу клиентов или делать с ней все, что вы хотите, при входе в систему она будет входить с привилегиями первого пользователя, которым часто может быть администратор.

Теперь параметризованные запросы делаютэто иначе, с кодом вроде:

sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'

parameters.add ("Пользователь", имя пользователя) parameters.add ("Пароль", пароль)

, где имя пользователя и пароль являются переменными, указывающими насоответствующее введенное имя пользователя и пароль

Теперь вы можете подумать, что это ничего не меняет.Конечно, вы все еще можете просто вставить в поле имени пользователя что-то вроде Nobody OR 1 = 1 '-, эффективно сделав запрос:

sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND
Pass=?'

И это может показаться действительным аргументом.Но вы были бы не правы.

Способ работы параметризованных запросов заключается в том, что sqlQuery отправляется как запрос, и база данных точно знает, что будет делать этот запрос, и только тогда она будет вставлять имя пользователя и пароли.просто как ценности.Это означает, что они не могут повлиять на запрос, потому что база данных уже знает, что будет делать запрос.Таким образом, в этом случае он будет искать имя пользователя "Nobody OR 1=1'--" и пустой пароль, который должен быть ложным.

Взято из

2 голосов
/ 29 марта 2011

Параметризованные запросы обрабатывают все - зачем идти на неприятности?

С параметризованными запросами, помимо общего внедрения, вы получаете все типы данных, которые обрабатываются: числа (целые и плавающие), строки (со встроенными кавычками), даты и время (без проблем форматирования или локализации при .ToString () не вызывается с инвариантной культурой, и ваш клиент перемещается на компьютер с неожиданным форматом даты).

1 голос
/ 17 марта 2016

Вполне понятно, почему так хочется.

sqlQuery = "select * from users where username='+username+';"

против

sqlQuery = "select * from users where username=@username;"

Похоже, что оба приведенных выше запроса делают одно и то же. Но на самом деле это не так.

Первый использует входные данные для запроса, второй принимает решение по запросу, но заменяет входные данные только такими, какими они являются во время выполнения запроса.

Для большей ясности, значения параметров расположены где-то в стеке, где хранится память переменных, и используются для поиска при необходимости.

Таким образом, если бы мы указали ' OR '1'='1 в качестве ввода в имени пользователя, первый * динамически построил бы новые запросы или запросы как часть строки запроса sql sqlQuery, которая затем выполняется.

Находясь на том же входе, последний будет искать ' OR '1'=' в поле username таблицы users с указанным статически запросом в строке запроса sqlQuery

Просто для консолидации, вот как вы используете параметры для создания запроса:

SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection);

SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@username";
parameter.Value = "xyz";

command.Parameters.Add(parameter);
1 голос
/ 29 марта 2011

Параметризованные запросы позволяют клиенту передавать данные отдельно от текста запроса.Где на большинстве свободных от текста вы бы сделали проверку + выход.Конечно, параметризация не помогает против других видов внедрения, но, поскольку параметр передается отдельно, он не используется как текстовый запрос выполнения.

Хорошей аналогией будет бит недавнего выполнения, используемый с большинствомсовременного процессора и операционной системы для защиты от переполнения буфера.Это по-прежнему допускает переполнение буфера, но предотвращает выполнение введенных данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...