Если да, почему все еще так много успешных инъекций SQL? Просто потому, что некоторые разработчики слишком глупы, чтобы использовать параметризованные утверждения?
Может ли параметризованный оператор остановить всю инъекцию SQL?
Ответ 1
Ссылки, которые я опубликовал в моих комментариях к вопросу, очень хорошо объясняют проблему. Я подытожил свои чувства о том, почему проблема сохраняется, ниже:
-
Те, кто только начинает, могут не знать об инъекции SQL.
-
Некоторые из них знают о SQL-инъекции, но считают, что экранирование - это (только?) решение. Если вы выполните быстрый поиск Google
php mysql query
, первая страница появится на страницеmysql_query
, на которой есть пример, который показывает интерполяцию экранированного пользовательского ввода в запрос. Там не упоминается (по крайней мере, не то, что я вижу) использования готовых инструкций. Как говорили другие, существует так много учебных пособий, которые используют интерполяцию параметров, что на самом деле не удивительно, как часто она все еще используется. -
Отсутствие понимания того, как работают параметризованные операторы. Некоторые считают, что это просто фантастическое средство избежать ценностей.
-
Другие знают о параметризованных операторах, но не используют их, потому что слышали, что они слишком медленные. Я подозреваю, что многие люди слышали, как невероятно медленные фразовые высказывания, но на самом деле не проводили никаких собственных испытаний. Как отметил Билл Карвин в своем выступлении, разница в производительности редко должна использоваться в качестве фактора при рассмотрении использования подготовленных заявлений. Преимущества подготовки один раз, выполнить многие, часто, как представляется, забыты, а также улучшения безопасности и надежности кода.
-
Некоторые используют параметризованные операторы везде, но с интерполяцией непроверенных значений, таких как имена таблиц и столбцов, ключевые слова и условные операторы. Основными примерами этого являются динамические поиски, такие как те, которые позволяют пользователям указывать несколько разных полей поиска, условия сравнения и порядок сортировки.
-
Ложное чувство безопасности при использовании ORM. ORM все еще разрешают интерполяцию частей инструкции SQL - см. 5.
-
Программирование - большой и сложный вопрос, управление базами данных - это большой и сложный вопрос, безопасность - большой и сложный вопрос. Разработка безопасного приложения базы данных непросто - даже опытные разработчики могут быть пойманы.
-
Многие ответы на stackoverflow не помогают. Когда люди пишут вопросы, которые используют динамический SQL и интерполяцию параметров, часто возникает нехватка ответов, которые предполагают использование параметризованных утверждений. В некоторых случаях у меня были люди, опровергающие мое предложение использовать подготовленные заявления - обычно из-за воспринимаемых неприемлемых служебных расходов. Я серьезно сомневаюсь, что те, кто задает большинство этих вопросов, находятся в положении, когда дополнительные несколько миллисекунд, принятые для подготовки параметризованного утверждения, окажут катастрофическое влияние на их применение.
Ответ 2
Когда в статьях рассказывается о параметризованных запросах, останавливающих атаки 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)
где username и 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.
Ответ 3
Ну, хороший вопрос. Ответ скорее стохастический, чем детерминированный, и я попытаюсь объяснить свое мнение на небольшом примере.
В сети есть много ссылок, которые предлагают нам использовать параметры в наших запросах или использовать хранимую процедуру с параметрами, чтобы избежать 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 = '''[email protected]+''' and usrPass = '''[email protected]+''''
execute(@sql)
Вы можете получить результаты, передав в качестве параметров имя пользователя и пароль. Предположим, что пароль находится в свободном тексте (просто для простоты этого примера), обычный вызов будет:
DECLARE @RC int
DECLARE @name varchar(20)
DECLARE @pass varchar(20)
EXECUTE @RC = [dbo].[getUser]
@name = 'admin'
,@pass = '[email protected]@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 и как ее можно выполнить, а затем соответствующим образом защитить свой код. Слепое следование "лучшим практикам" не всегда является более безопасным способом... и, возможно, именно поэтому у нас так много "лучших практик" - неудач!
Ответ 4
Да, использование подготовленных операторов останавливает все инъекции SQL, по крайней мере теоретически. На практике параметризованные операторы могут быть не реальными подготовленными операциями, например. PDO
в PHP имитирует их по умолчанию, чтобы открывать атаку на кромку.
Если вы используете реальные подготовленные заявления, все в порядке. Ну, по крайней мере, пока вы не объединяете небезопасный SQL в свой запрос, как реакцию на невозможность подготовить имена таблиц, например.
Если да, почему все еще так много успешных инъекций SQL? Просто потому, что некоторые разработчики слишком глупы, чтобы использовать параметризованные утверждения?
Да, здесь основное внимание уделяется образованию и устаревшим кодам. К сожалению, многие учебники используют экранирование, и, к сожалению, их нельзя легко удалить из Интернета.
Ответ 5
Я избегаю абсолютов в программировании; всегда есть исключение. Я настоятельно рекомендую хранимые процедуры и объекты команд. Большая часть моей базы с SQL Server, но я играю с MySql время от времени. Существует множество преимуществ хранимых процедур, включая кэшированные планы запросов; да, это может быть достигнуто с помощью параметров и встроенного SQL, но это открывает больше возможностей для инъекционных атак и не помогает с разделением проблем. Для меня также намного проще обеспечить безопасность базы данных, так как мои приложения обычно имеют только разрешение на выполнение указанных хранимых процедур. Без прямого доступа к таблице/представлению гораздо сложнее вводить что-либо. Если пользователь приложений скомпрометирован, у него есть только разрешение на выполнение именно того, что было определено заранее.
Мои два цента.
Ответ 6
Я бы не сказал "тупой".
Я думаю, что учебники - это проблема. Большинство учебников по SQL, книги, все, что объясняет SQL со встроенными значениями, вообще не упоминают параметры привязки. Люди, изучающие эти учебные пособия, не имеют возможности изучить его правильно.
Ответ 7
Поскольку большинство кода не написано с учетом безопасности и управления, учитывая выбор между добавлением функций (особенно что-то видимое, которое можно продать) и безопасностью/стабильностью/надежностью (что намного сложнее продать), они будут почти неизменно выбирают первое. Безопасность является лишь проблемой, когда она становится проблемой.
Ответ 8
Может ли параметризованный оператор остановить все SQL-инъекции?
Да, если ваш драйвер базы данных предлагает местозаполнитель для каждого возможного литерала SQL. В большинстве подготовленных драйверов инструкций нет. Скажем, вы никогда не найдете местозаполнитель для имени поля или массива значений. Это заставит разработчика откидываться назад на посылку запроса вручную, используя конкатенацию и ручное форматирование. С прогнозируемым результатом.
Вот почему я сделал свою Mysql-оболочку для PHP, которая поддерживает большинство литералов, которые могут быть добавлены в запрос динамически, включая массивы и идентификаторы.
Если да, почему все еще так много успешных инъекций SQL? Просто потому, что некоторые разработчики слишком глупы, чтобы использовать параметризованные утверждения?
Как вы можете видеть, на самом деле просто невозможно настроить все ваши запросы, даже если вы не тупой.
Ответ 9
Сначала мой ответ на ваш первый вопрос: Да, насколько я знаю, с помощью параметризованных запросов SQL-инъекции больше не будут возможны. Что касается ваших следующих вопросов, я не уверен и могу только высказать свое мнение по причинам:
Я думаю, что проще "просто" написать строку запроса SQL, объединив некоторые разные части (возможно, даже зависящие от некоторых логических проверок) вместе со значениями, которые нужно вставить. Он просто создает запрос и выполняет его. Другим преимуществом является то, что вы можете печатать (эхо, вывод или что-то еще) строку запроса sql, а затем использовать эту строку для ручного запроса к движку базы данных.
При работе с подготовленными заявлениями вы всегда имеете хотя бы один шаг: Вы должны построить свой запрос (включая параметры, конечно) Вы должны подготовить запрос на сервере Вы должны привязать параметры к фактическим значениям, которые вы хотите использовать для своего запроса Вы должны выполнить запрос.
Это несколько больше работает (и не так просто программировать), особенно для некоторых "быстрых и грязных" заданий, которые часто оказываются очень долговечными...
С уважением,
Вставка
Ответ 10
Чтобы защитить приложение от SQL-инъекции, выполните следующие действия:
Шаг 1. Ограничьте ввод. Шаг 2. Используйте параметры с хранимыми процедурами. Шаг 3. Используйте параметры с динамическим SQL.
Обратитесь к http://msdn.microsoft.com/en-us/library/ff648339.aspx
Ответ 11
SQL-инъекция - это подмножество большей проблемы ввода кода, где данные и код предоставляются по одному каналу, а данные ошибочны для кода. Параметрированные запросы предотвращают это, формируя запрос, используя контекст о том, что такое данные и что такое код.
В некоторых конкретных случаях этого недостаточно. Во многих СУБД можно динамически выполнять SQL с хранимыми процедурами, представляя ошибку SQL-инъекции на уровне СУБД. Вызов такой хранимой процедуры с использованием параметризованных запросов не будет препятствовать использованию SQL-инъекции в процедуре. Другой пример можно увидеть в этом сообщении в блоге.
Чаще всего разработчики неправильно используют эту функцию. Обычно код выглядит примерно так, когда выполняется правильно:
db.parameterize_query("select foo from bar where baz = '?'", user_input)
Некоторые разработчики объединяют строки вместе, а затем используют параметризованный запрос, который фактически не делает вышеупомянутое разграничение данных/кода, которое обеспечивает гарантии безопасности, которые мы ищем:
db.parameterize_query("select foo from bar where baz = '" + user_input + "'")
Правильное использование параметризованных запросов обеспечивает очень прочную, но непроницаемую защиту от атак SQL-инъекций.
Ответ 12
даже если подготовленные заявления правильно используются во всех веб-приложениях кода, недостатки внедрения 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
Даже если приложение передает введенное пользователем значение имени в сохраненный процедура безопасным образом, сама процедура объединяет это непосредственно в динамический запрос и, следовательно, уязвим.