Идея очень проста - запрос и данные отправляются на сервер базы данных отдельно .
Вот и все.
Корень проблемы внедрения SQL-кода заключается в смешении кода и данных.
На самом деле, наш SQL-запрос является законной программой . И мы создаем такую программу динамически, добавляя некоторые данные на лету. Таким образом, данные могут мешать программному коду и даже изменять его, как показывает каждый пример внедрения SQL (все примеры в PHP / Mysql):
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
будет производить обычный запрос
SELECT * FROM users where id=1
пока этот код
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
будет выдавать вредоносную последовательность
SELECT * FROM users where id=1; DROP TABLE users;
Это работает, потому что мы добавляем данные непосредственно в тело программы, и они становятся частью программы, поэтому данные могут изменить программу, и в зависимости от переданных данных у нас будет либо обычный вывод, либо таблица будет users
удалена.
Хотя в случае подготовленных утверждений мы не изменяем нашу программу, она остается неизменной
.
Сначала мы отправляем программу на сервер
$db->prepare("SELECT * FROM users where id=?");
где данные заменяются некоторой переменной, называемой параметром или заполнителем.
Обратите внимание, что на сервер отправляется точно такой же запрос без каких-либо данных! И затем мы отправляем данные со вторым запросом, по существу отделенным от самого запроса:
$db->execute($data);
поэтому он не может изменить нашу программу и причинить какой-либо вред.
Довольно просто - не так ли?
Единственное, что я должен добавить, это всегда опускается в каждом руководстве:
Подготовленные операторы могут защищать только литералы данных , но не могут использоваться с любой другой частью запроса.
Так что, как только мы добавим, скажем, динамический идентификатор - например, имя поля - подготовленные операторы не смогут нам помочь. Я недавно объяснил этот вопрос , поэтому я не буду повторяться.
$spoiled_data = "1; DROP TABLE users;"
->$query = "SELECT * FROM users where id=$spoiled_data";
, по сравнению с:$db->prepare("SELECT * FROM users where id=?");
->$data = "1; DROP TABLE users;"
->$db->execute($data);
. Разве они не сделают то же самое?Вот SQL для настройки примера:
Класс Inject уязвим для внедрения SQL. Запрос динамически вставляется вместе с пользовательским вводом. Целью запроса было показать информацию о Бобе. Заработная плата или бонус, в зависимости от ввода пользователя. Но злонамеренный пользователь манипулирует вводом, повреждая запрос, прикрепляя эквивалент выражения «или true» к предложению where, чтобы все возвращалось, включая информацию об Аароне, который должен был быть скрыт.
Выполнение этого, первый случай с нормальным использованием, а второй с вредоносной инъекцией:
Вы не должны создавать свои операторы SQL с конкатенацией ввода пользователя. Он не только уязвим для внедрения, но также имеет последствия для кэширования на сервере (оператор изменяется, поэтому вероятность попадания в кэш операторов SQL снижается, тогда как в примере связывания всегда выполняется один и тот же оператор).
Вот пример Binding, чтобы избежать такого рода инъекций:
Выполнение этого с тем же вводом, что и в предыдущем примере, показывает, что вредоносный код не работает, потому что нет платежного типа, соответствующего этой строке:
источник
PREPARE
создает фиксированный именованный оператор, который уже проанализирован (т. е. оператор больше не будет изменяться независимо от входных данных), покаEXECUTE
будет выполняться именованный оператор, связывающий параметры. Поскольку онPREPARE
имеет только длительность сеанса, похоже, он предназначен для повышения производительности, а не для предотвращения внедрения через сценарии psql. Для доступа psql, может дать разрешения для хранимых процедур и связать параметры в процессах.По сути, с подготовленными утверждениями данные, поступающие от потенциального хакера, обрабатываются как данные - и нет никакого способа, которым они могут быть смешаны с SQL вашего приложения и / или интерпретированы как SQL (что может случиться, когда передаваемые данные помещаются непосредственно в ваш приложение SQL).
Это связано с тем, что подготовленные операторы сначала «подготавливают» запрос SQL, чтобы найти эффективный план запроса, и позже отправляют фактические значения, которые предположительно поступают из формы, - тогда запрос фактически выполняется.
Более подробная информация здесь:
Подготовленные операторы и SQL-инъекция
источник
Я прочитал ответы и все еще чувствовал необходимость подчеркнуть ключевой момент, который освещает суть подготовленных заявлений. Рассмотрим два способа сделать запрос к базе данных, в которую вовлечен пользовательский ввод:
Наивный подход
Один объединяет пользовательский ввод с некоторой частичной строкой SQL для генерации оператора SQL. В этом случае пользователь может встроить вредоносные команды SQL, которые затем будут отправлены в базу данных для выполнения.
Например, злонамеренный ввод пользователя может привести
SQLString
к"SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
Из-за злонамеренного пользователя,
SQLString
содержит 2 утверждения, где 2-е ("DROP TABLE CUSTOMERS"
) нанесет вред.Подготовленные заявления
В этом случае из-за разделения запроса и данных пользовательский ввод никогда не обрабатывается как оператор SQL и, следовательно, никогда не выполняется . По этой причине любой введенный вредоносный код SQL не причинит вреда. Таким образом
"DROP TABLE CUSTOMERS"
, никогда не будет выполнено в случае выше.Короче говоря, с подготовленными утверждениями вредоносный код, введенный через пользовательский ввод, не будет выполнен!
источник
Когда вы создаете и отправляете подготовленный оператор в СУБД, он сохраняется как запрос SQL для выполнения.
Позже вы связываете свои данные с запросом, так что СУБД использует эти данные в качестве параметров запроса для выполнения (параметризации). СУБД не использует данные, которые вы связываете, в качестве дополнения к уже скомпилированному запросу SQL; это просто данные.
Это означает, что принципиально невозможно выполнить SQL-инъекцию, используя подготовленные операторы. Этому препятствует сама природа подготовленных заявлений и их связь с СУБД.
источник
В SQL Server использование подготовленного оператора определенно защищено от инъекций, поскольку входные параметры не формируют запрос. Это означает, что выполненный запрос не является динамическим запросом. Пример уязвимого оператора SQL-инъекции.
Теперь, если значение в переменной inoutusername является чем-то вроде 'или 1 = 1 -, этот запрос теперь становится:
А остальное комментируется после
--
, так что оно никогда не выполняется и не игнорируется, как в примере с подготовленным оператором, как показано ниже.Таким образом, в действительности вы не можете отправить другой параметр, таким образом избегая SQL-инъекций ...
источник
Ключевая фраза есть
need not be correctly escaped
. Это означает, что вам не нужно беспокоиться о людях, которые пытаются добавить тире, апострофы, цитаты и т. Д.Это все обрабатывается для вас.
источник
Давайте предположим, что вы имеете это в сервлете, вы правы. Если злонамеренный человек передал неправильное значение для «фильтра», вы можете взломать вашу базу данных.
источник
Причина № 1 - Проблема с разделителем
Внедрение Sql возможно потому, что мы используем кавычки для разделения строк, а также для того, чтобы быть частью строк, что иногда делает невозможным их интерпретацию. Если бы у нас были разделители, которые нельзя было использовать в строковых данных, SQL-инъекция никогда бы не произошла. Решение проблемы с разделителем устраняет проблему внедрения SQL. Структурные запросы делают это.
Причина № 2 - человеческая природа, люди лукавые, а некоторые лукавые люди злые, и все люди совершают ошибки
Другой основной причиной инъекции sql является человеческая природа. Люди, в том числе программисты, делают ошибки. Когда вы делаете ошибку в структурированном запросе, это не делает вашу систему уязвимой для внедрения SQL. Если вы не используете структурированные запросы, ошибки могут привести к уязвимости SQL инъекций.
Как структурированные запросы устраняют первопричины SQL-инъекций
Структурированные запросы Решают проблему разделителя, помещая команды sql в один оператор и помещая данные в отдельный оператор программирования. Заявления программирования создают необходимое разделение.
Структурированные запросы помогают предотвратить человеческие ошибки от создания критических дыр в безопасности. Что касается людей, совершающих ошибки, SQL-инъекция не может произойти при использовании структурных запросов. Существуют способы предотвращения внедрения SQL, которые не включают структурированные запросы, но обычная человеческая ошибка в таких подходах обычно приводит к некоторому риску внедрения SQL. Структурированные запросы отказоустойчивы от внедрения SQL. Вы можете совершать все ошибки в мире, почти с помощью структурированных запросов, как и любое другое программирование, но ни одна из возможных ошибок не может быть превращена в систему, перенесенную с помощью SQL-инъекции. Вот почему люди любят говорить, что это правильный способ предотвратить инъекцию SQL.
Итак, у вас есть это, причины внедрения SQL и характер структурированных запросов, которые делают их невозможными при их использовании.
источник