Может ли параметризованный оператор остановить все внедрения SQL? - PullRequest
70 голосов
/ 22 июля 2011

Если да, почему все еще так много успешных SQL-инъекций? Только потому, что некоторые разработчики слишком тупы, чтобы использовать параметризованные операторы?

Ответы [ 12 ]

59 голосов
/ 22 июля 2011

Ссылки, которые я разместил в своих комментариях к вопросу, очень хорошо объясняют проблему.Ниже я кратко изложил свои чувства о том, почему проблема сохраняется:

  1. Те, кто только начинает работать, могут не знать о внедрении SQL.

  2. Некоторые знают о внедрении SQL, но думают, что экранирование является (единственным?) Решением.Если вы выполните быстрый поиск в Google по номеру php mysql query, первой страницей, которая появится, будет страница mysql_query, на которой есть пример, показывающий интерполяцию экранированного пользовательского ввода в запрос.Там нет упоминания (по крайней мере, что я не вижу) об использовании подготовленных утверждений вместо этого.Как говорили другие, существует так много учебных пособий, в которых используется интерполяция параметров, поэтому неудивительно, насколько часто они по-прежнему используются.

  3. Отсутствие понимания того, как работают параметризованные операторы,Некоторые думают, что это просто причудливый способ избежать ценностей.

  4. Другие знают о параметризованных утверждениях, но не используют их, потому что слышали, что они слишком медленные.Я подозреваю, что многие люди слышали о том, как невероятно медленные парамализированные утверждения, но на самом деле не проводили никакого собственного тестирования.Как отметил в своем выступлении Билл Карвин, различие в производительности редко следует использовать в качестве фактора при рассмотрении вопроса об использовании подготовленных утверждений.Преимущества подготовить один раз, выполнить множество , часто кажутся забытыми, равно как и улучшения в области безопасности и удобства сопровождения кода.

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

  6. Ложное чувство безопасности при использовании ORM,ORM по-прежнему допускают интерполяцию частей операторов SQL - см. 5.

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

  8. Многие ответы на stackoverflow не помогают.Когда люди пишут вопросы, использующие динамический SQL и интерполяцию параметров, часто не хватает ответов, которые предлагают вместо этого использовать параметризованные операторы.В некоторых случаях мне предлагали опровергнуть мое предложение использовать подготовленные операторы - как правило, из-за неприемлемого снижения производительности.Я серьезно сомневаюсь, что те, кто задает большинство из этих вопросов, находятся в состоянии, когда дополнительные несколько миллисекунд, затраченные на подготовку параметризованного утверждения, окажут катастрофическое влияние на их применение.

44 голосов
/ 09 октября 2015

Когда в статьях говорится о параметризованных запросах, останавливающих атаки SQL, они на самом деле не объясняют почему, часто это так: «Да, не спрашивайте почему» - возможно, потому, что они сами не знают.Верным признаком плохого воспитателя является тот, который не может признать, что они ничего не знают.Но я отвлекся.Когда я говорю, что совершенно понятно, что запутаться - это просто.Представьте себе динамический SQL-запрос

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

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

sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS=' + password

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

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

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

parameters.add("User", username)
parameters.add("Pass", password)

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

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

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

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

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

Это не полное решение и проверка вводавсе еще нужно будет сделать, так как это не повлияет на другие проблемы, такие как атаки XSS, так как вы все равно можете поместить javascript в базу данных.Затем, если это будет считано на странице, он будет отображаться как обычный javascript, в зависимости от проверки вывода.Поэтому лучше всего по-прежнему использовать проверку ввода, но использовать параметризованные запросы или хранимые процедуры, чтобы остановить любые атаки SQL.

10 голосов
/ 10 октября 2015

Ну, хороший вопрос.Ответ скорее стохастический, чем детерминированный, и я попытаюсь объяснить свое мнение на небольшом примере.

В сети много ссылок, которые предлагают нам использовать параметры в наших запросах или использовать хранимую процедуру с параметрами вЧтобы избежать SQL-инъекций (SQLi).Я покажу вам, что хранимые процедуры (например) не волшебная палочка против SQLi.Ответственность остается за программистом.

Рассмотрим следующую хранимую процедуру SQL Server, которая получит строку пользователя из таблицы «Пользователи»:

create procedure getUser
 @name varchar(20)
,@pass varchar(20)
as
declare @sql as nvarchar(512)
set @sql = 'select usrID, usrUName, usrFullName, usrRoleID '+
           'from Users '+
           'where usrUName = '''+@name+''' and usrPass = '''+@pass+''''
execute(@sql)

Вы можете получить результаты, передавв качестве параметров имя пользователя и пароль.Предположим, что пароль находится в свободном тексте (просто для простоты этого примера) нормальный вызов будет:

DECLARE @RC int
DECLARE @name varchar(20)
DECLARE @pass varchar(20)

EXECUTE @RC = [dbo].[getUser] 
   @name = 'admin'
  ,@pass = '!@Th1siSTheP@ssw0rd!!'
GO

Но здесь у нас есть плохая методика программирования, используемая программистом внутри хранимой процедуры, поэтому злоумышленникможет выполнить следующее:

DECLARE @RC int
DECLARE @name varchar(20)
DECLARE @pass varchar(20)

EXECUTE @RC = [TestDB].[dbo].[getUser] 
   @name = 'admin'
  ,@pass = 'any'' OR 1=1 --'
GO

Вышеуказанные параметры будут переданы в качестве аргументов хранимой процедуре, и команда SQL, которая в конечном итоге будет выполнена, будет:

select usrID, usrUName, usrFullName, usrRoleID 
from Users 
where usrUName = 'admin' and usrPass = 'any' OR 1=1 --'

.. которая будетполучить все строки обратно от пользователей

Проблема здесь в том, что даже мы следуем принципу «Создаем хранимую процедуру и передаем поля для поиска в качестве параметров», SQLi все еще выполняется.Это потому, что мы просто копируем нашу плохую практику программирования в хранимую процедуру.Решение проблемы состоит в том, чтобы переписать нашу хранимую процедуру следующим образом:

alter procedure getUser
 @name varchar(20)
,@pass varchar(20)
as
select usrID, usrUName, usrFullName, usrRoleID 
from Users 
where usrUName = @name and usrPass = @pass

Я хочу сказать, что разработчики должны сначала узнать, что такое атака SQLi и как ее можно выполнить, а затем защититьих код соответственно.Слепое следование «лучшим практикам» не всегда является более безопасным способом ... и, возможно, именно поэтому у нас так много «лучших практик» - неудачи!

5 голосов
/ 09 октября 2015

Да, использование подготовленных операторов останавливает все SQL-инъекции, по крайней мере, теоретически. На практике параметризованные утверждения не могут быть реально подготовленными утверждениями, например, PDO в PHP эмулирует их по умолчанию, поэтому он открыт для атаки в крайнем случае .

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

Если да, почему все еще так много успешных SQL-инъекций? Только потому, что некоторые разработчики слишком тупы, чтобы использовать параметризованные операторы?

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

3 голосов
/ 14 октября 2015

Я избегаю абсолютов в программировании; всегда есть исключение. Я настоятельно рекомендую хранимые процедуры и объекты команд. Большая часть моего опыта работы с SQL Server, но я время от времени играю с MySql. У хранимых процедур есть много преимуществ, включая кэшированные планы запросов; да, это может быть достигнуто с помощью параметров и встроенного SQL, но это открывает больше возможностей для инъекционных атак и не помогает в разделении проблем. Для меня также намного проще защитить базу данных, поскольку мои приложения обычно имеют разрешение на выполнение только для указанных хранимых процедур. Без прямого доступа к таблице / представлению гораздо сложнее что-либо внедрить. Если пользователь приложения скомпрометирован, у него есть только разрешение на выполнение именно того, что было предопределено.

Мои два цента.

2 голосов
/ 14 октября 2015

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

Я думаю, что проще "просто" написать строку запроса SQL, объединив несколько различных частей (возможно, даже зависящих от некоторых логических проверок) вместе со значениями, которые нужно вставить. Это просто создание запроса и его выполнение. Другое преимущество состоит в том, что вы можете напечатать (echo, output или что-то еще) строку запроса sql, а затем использовать эту строку для ручного запроса к ядру базы данных.

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

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

С уважением,

Box

2 голосов
/ 09 октября 2015

Может ли параметризованный оператор остановить все SQL-инъекции?

Да, если драйвер вашей базы данных предлагает заполнитель для каждого возможного литерала SQL. В большинстве подготовленных драйверов операторов этого нет. Скажем, вы никогда не найдете заполнителя для имени поля или для массива значений. Что заставит разработчика вернуться к настройке запроса вручную, используя конкатенацию и ручное форматирование. С прогнозируемым исходом.

Именно поэтому я создал свою оболочку Mysql для PHP, которая поддерживает большинство литералов, которые можно динамически добавлять к запросу, включая массивы и идентификаторы.

Если да, почему все еще так много успешных SQL-инъекций? Просто потому, что некоторые разработчики слишком тупы, чтобы использовать параметризованные операторы?

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

2 голосов
/ 22 июля 2011

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

2 голосов
/ 22 июля 2011

Я бы не сказал "тупой".

Я думаю, что учебники - это проблема. В большинстве учебных пособий по SQL, книг, которые бы ни объясняли SQL со встроенными значениями, не упоминая параметры связывания вообще. Люди, изучающие эти уроки, не имеют возможности выучить это правильно.

1 голос
/ 15 августа 2018

, даже если подготовленные операторы правильно используются в собственном коде веб-приложения, недостатки внедрения SQL могут все еще существовать, если компоненты кода базы данных создают запросы из пользовательского ввода небезопасным способом.Ниже приведен пример хранимой процедуры, которая уязвима для внедрения SQL в параметре @name:

CREATE PROCEDURE show_current_orders
(@name varchar(400) = NULL)
AS
DECLARE @sql nvarchar(4000)
SELECT @sql = ‘SELECT id_num, searchstring FROM searchorders WHERE ‘ +
‘searchstring = ‘’’ + @name + ‘’’’;
EXEC (@sql)
GO

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

...