Могу ли я защититься от SQL-инъекции, избегая одиночных кавычек и заключая пользовательский ввод в одинарные кавычки?
-
02-07-2019 - |
Вопрос
Я понимаю, что параметризованные SQL-запросы — это оптимальный способ очистки пользовательского ввода при построении запросов, содержащих пользовательский ввод, но мне интересно, что плохого в том, чтобы принимать пользовательский ввод, экранировать любые одинарные кавычки и заключать всю строку в одинарные кавычки.Вот код:
sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"
Любая одинарная кавычка, которую вводит пользователь, заменяется двойными одинарными кавычками, что исключает возможность пользователя завершать строку, поэтому все остальное, что он может ввести, например точки с запятой, знаки процента и т. д., будет частью строки, а не фактически выполняется как часть команды.Мы используем Microsoft SQL Server 2000, для которого, я считаю, одинарные кавычки являются единственным разделителем строк и единственным способом избежать разделителя строк, поэтому невозможно выполнить что-либо, что вводит пользователь.
Я не вижу никакого способа начать атаку с помощью SQL-инъекций против этого, но я понимаю, что если бы это было так пуленепробиваемо, как мне кажется, кто-то другой уже подумал бы об этом, и это было бы обычной практикой.Мой вопрос таков:что не так с этим кодом?Кто-нибудь знает способ обойти эту технику очистки с помощью SQL-инъекции?Пример пользовательского ввода, использующего эту технику, был бы очень полезен.
ОБНОВЛЯТЬ:
Спасибо всем за ответы;почти вся информация, с которой я столкнулся в ходе своего исследования, появилась где-то на этой странице, что является признаком интеллекта и навыков людей, которые нашли время в свои напряженные дни, чтобы помочь мне с этим вопросом.
Причина, по которой я до сих пор не принял ни одного ответа, заключается в том, что я до сих пор не знаю никакого способа эффективно запустить атаку с помощью SQL-инъекции на этот код.Несколько человек предположили, что обратная косая черта будет экранировать одну одинарную кавычку и оставить другую для завершения строки, чтобы остальная часть строки выполнялась как часть команды SQL, и я понимаю, что этот метод будет работать для внедрения SQL в база данных mySQL, но в MS SQL 2000 единственный способ (который мне удалось найти) избежать одиночной кавычки - это использовать другую одинарную кавычку;обратная косая черта этого не сделает.И если не существует способа остановить экранирование одинарной кавычки, остальная часть пользовательского ввода не будет выполнена, поскольку все они будут восприниматься как одна непрерывная строка.
Я понимаю, что есть более эффективные способы очистки ввода, но мне действительно больше интересно узнать, почему метод, указанный выше, не работает.Если кто-нибудь знает какой-либо конкретный способ проведения атаки SQL-инъекцией против этого метода очистки, я бы хотел его увидеть.
Решение
Прежде всего, это просто плохая практика.Проверка ввода всегда необходима, но она также всегда сомнительна.
Хуже того, проверка черного списка всегда проблематична, гораздо лучше явно и строго определить, какие значения/форматы вы принимаете.Правда, это не всегда возможно – но в какой-то степени это нужно делать всегда.
Некоторые научные статьи на эту тему:
- http://www.imperva.com/docs/WP_SQL_Injection_Protection_LK.pdf
- http://www.it-docs.net/ddata/4954.pdf (Признаюсь, последний был моим;) )
- https://www.owasp.org/images/d/d4/OWASP_IL_2007_SQL_Smuggling.pdf (на основе предыдущей статьи, которая больше не доступна)
Дело в том, что любой черный список, который вы составляете (и слишком разрешительные белые списки), можно обойти.Последняя ссылка на мою статью показывает ситуации, когда можно обойти даже экранирование кавычек.
Даже если эти ситуации к вам не относятся, это все равно плохая идея.Более того, если ваше приложение не тривиально маленькое, вам придется иметь дело с обслуживанием и, возможно, с определенным уровнем управления:как вы гарантируете, что все будет сделано правильно, везде и всегда?
Правильный способ сделать это:
- Проверка белого списка:тип, длина, формат или принятые значения
- Если вы хотите внести в черный список, продолжайте.Экранирование кавычек — это хорошо, но в контексте других мер по смягчению последствий.
- Используйте объекты команд и параметров для подготовки и проверки.
- Вызывайте только параметризованные запросы.
- А еще лучше использовать исключительно хранимые процедуры.
- Избегайте использования динамического SQL и не используйте конкатенацию строк для построения запросов.
- При использовании SP вы также можете ограничить разрешения в базе данных только для выполнения необходимых SP, а не для прямого доступа к таблицам.
- вы также можете легко убедиться, что вся кодовая база обращается к БД только через SP...
Другие советы
Хорошо, этот ответ будет относиться к обновлению вопроса:
«Если кто-нибудь знает какой-либо конкретный способ проведения атаки SQL-инъекцией против этого метода очистки, я бы хотел его увидеть».
Теперь, помимо экранирования обратной косой черты MySQL - и принимая во внимание, что мы на самом деле говорим о MSSQL, на самом деле существует 3 возможных способа внедрения SQL в ваш код.
sSanitizedInput = "'" & replace(sInput, "'", "''") & "'"
Учтите, что не все они будут действительны всегда и во многом зависят от вашего фактического кода:
- SQL-инъекция второго порядка — если SQL-запрос перестраивается на основе данных, полученных из базы данных. после побега, данные объединяются без экранирования и могут быть косвенно внедрены с помощью SQL.Видеть
- Усечение строки (немного сложнее). Сценарий: у вас есть два поля, скажем, имя пользователя и пароль, и SQL объединяет их оба.И оба поля (или только первое) имеют жесткое ограничение по длине.Например, имя пользователя ограничено 20 символами.Скажем, у вас есть этот код:
username = left(Replace(sInput, "'", "''"), 20)
Тогда вы получите имя пользователя, экранированное, а затем обрезанное до 20 символов.Проблема здесь - я вставлю свою цитату в 20-й символ (например.после 19 а), и ваша экранирующая кавычка будет обрезана (в 21-м символе).Тогда SQL
sSQL = "select * from USERS where username = '" + username + "' and password = '" + password + "'"
в сочетании с вышеупомянутым неправильным именем пользователя приведет к тому, что пароль уже будет снаружи кавычки и будет содержать непосредственно полезную нагрузку.
3.Контрабанда Юникода. В определенных ситуациях можно передать символ Юникода высокого уровня, который выглядит как цитата, но не - пока не попадет в базу данных, откуда вдруг это.Поскольку это не цитата, когда вы ее проверяете, все пройдет легко...Более подробную информацию см. в моем предыдущем ответе и ссылку на оригинальное исследование.
В двух словах:Никогда не делайте запрос, ускользающий от себя.Вы обязательно поймете что-то не так.Вместо этого используйте параметризованные запросы или, если по какой-то причине вы не можете этого сделать, используйте существующую библиотеку, которая сделает это за вас.Нет причин делать это самостоятельно.
Я понимаю, что прошло много времени после того, как вопрос был задан, но..
Один из способов атаковать процедуру «цитирования аргумента» — усечение строки.Согласно MSDN, в SQL Server 2000 SP4 (и SQL Server 2005 SP1) слишком длинная строка будет незаметно усекаться.
Когда вы заключаете строку в кавычки, она увеличивается в размере.Каждый апостроф повторяется.Затем это можно использовать для вывода частей SQL за пределы буфера.Таким образом, вы можете эффективно удалить части предложенияwhere.
Вероятно, это было бы наиболее полезно в сценарии страницы «администратора пользователя», где вы могли бы злоупотребить оператором «обновления», чтобы не выполнять все проверки, которые он должен был выполнять.
Поэтому, если вы решите заключить в кавычки все аргументы, убедитесь, что вы знаете, что происходит с размерами строк, и следите за тем, чтобы не столкнуться с усечением.
Я бы рекомендовал использовать параметры.Всегда.Просто хотелось бы обеспечить это в базе данных.И как побочный эффект, вы с большей вероятностью получите лучшее попадание в кеш, потому что больше операторов выглядят одинаково.(Это, безусловно, было верно для Oracle 8)
Входная санитария – это не то, чем вы хотите заниматься наполовину.Используй всю свою задницу.Используйте регулярные выражения в текстовых полях.Попробуйте привести числовые значения к правильному числовому типу и сообщить об ошибке проверки, если это не сработает.Очень легко искать шаблоны атак во входных данных, например ' --.Предположим, что все вводимые пользователем данные являются враждебными.
Я использовал этот метод при работе с функцией «расширенного поиска», где единственным возможным решением было создание запроса с нуля.(Пример:позволяют пользователю искать продукты на основе неограниченного набора ограничений на атрибуты продуктов, отображая столбцы и их разрешенные значения в качестве элементов управления графического интерфейса, чтобы снизить порог обучения для пользователей.)
Само по себе это безопасно AFAIK.Однако, как отметил другой ответчик, вам также может потребоваться иметь дело с экранированием обратного пространства (хотя, по крайней мере, не при передаче запроса на SQL Server с использованием ADO или ADO.NET - не могу ручаться за все базы данных или технологии).
Загвоздка в том, что вам действительно нужно быть уверенным, какие строки содержат пользовательский ввод (всегда потенциально вредоносный), а какие строки являются допустимыми запросами SQL.Одна из ловушек заключается в том, что если вы используете значения из базы данных, были ли эти значения изначально предоставлены пользователем?Если это так, их также необходимо избежать.Мой ответ — попытаться выполнить санацию как можно позже (но не позже!), при построении SQL-запроса.
Однако в большинстве случаев привязка параметров — это лучший способ — это проще.
В любом случае, это плохая идея, как вы, кажется, знаете.
А как насчет чего-то вроде экранирования кавычки в строке следующим образом:\'
Ваша замена приведет к:\''
Если обратная косая черта выходит за пределы первой кавычки, вторая кавычка завершает строку.
Простой ответ:Иногда это будет работать, но не всегда.Вы хотите использовать проверку белого списка на все да, но я понимаю, что это не всегда возможно, поэтому вы вынуждены использовать черный список с лучшим предположением.Аналогично, вы хотите использовать параметризованные хранимые процедуры в все, но опять же, это не всегда возможно, поэтому вам придется использовать sp_execute с параметрами.
Есть способы обойти любой полезный черный список, который вы можете придумать (а также некоторые белые списки).
Достойная запись здесь: http://www.owasp.org/index.php/Top_10_2007-A2
Если вам нужно сделать это в качестве быстрого решения, чтобы дать вам время установить настоящее, сделайте это.Но не думайте, что вы в безопасности.
Есть два способа сделать это, без исключений, чтобы обезопасить себя от SQL-инъекций;подготовленные операторы или параметризованные хранимые процедуры.
Если у вас есть параметризованные запросы, вы должны использовать их всегда.Достаточно одного запроса, чтобы проскользнуть через сеть, и ваша БД окажется под угрозой.
Да, это должно работать до тех пор, пока кто-нибудь не сбежит. ВЫКЛЮЧИТЬ QUOTED_IDENTIFIER и использует для вас двойные кавычки.
Редактировать:Это не так просто, как запретить злоумышленнику отключать идентификаторы в кавычках:
Драйвер ODBC собственного клиента SQL Server и поставщик OLE DB собственного клиента SQL Server для SQL Server автоматически устанавливают для QUOTED_IDENTIFIER значение ON при подключении.Это можно настроить в источниках данных ODBC, в атрибутах соединения ODBC или свойствах соединения OLE DB. По умолчанию для SET QUOTED_IDENTIFIER установлено значение OFF для соединений из приложений DB-Library.
При создании хранимой процедуры Параметры SET QUOTED_IDENTIFIER и SET ANSI_NULLS фиксируются и используются для последующих вызовов этой хранимой процедуры..
SET QUOTED_IDENTIFIER также соответствует настройке QUOTED_IDENTIFER в ALTER DATABASE.
SET QUOTED_IDENTIFIER устанавливается во время анализа.Установка во время анализа означает, что если оператор SET присутствует в пакете или хранимой процедуре, он вступает в силу независимо от того, достигает ли выполнение кода этой точки;и инструкция SET вступает в силу до выполнения каких-либо инструкций.
Есть много способов, которыми QUOTED_IDENTIFIER может быть отключен без вашего ведома.По общему признанию, это не тот эксплойт, который вы ищете, но это довольно большая поверхность атаки.Конечно, если вы еще и избежали двойных кавычек – то мы вернулись к тому, с чего начали.;)
Ваша защита потерпит неудачу, если:
- запрос ожидает число, а не строку
- существовал любой другой способ представления одинарной кавычки, в том числе:
- escape-последовательность, например \039
- символ Юникода
(в последнем случае это должно быть что-то, что было расширено только после того, как вы выполнили замену)
Патрик, ты заключаешь ВСЕ вводимые данные в одинарные кавычки, даже числовые?Если у вас есть числовой ввод, но вы не заключаете его в одинарные кавычки, то у вас есть риск.
Каким уродливым кодом была бы вся эта очистка пользовательского ввода!Затем неуклюжий StringBuilder для оператора SQL.Метод подготовленных операторов позволяет получить более чистый код, а преимущества внедрения SQL-кода являются действительно приятным дополнением.
И зачем изобретать велосипед?
Вместо того, чтобы заменять одинарную кавычку (как это выглядит) двумя одинарными кавычками, почему бы просто не заменить ее на апостроф, кавычку или полностью удалить?
В любом случае, это какой-то косяк...особенно если у вас есть законные вещи (например, имена), которые могут использовать одинарные кавычки...
ПРИМЕЧАНИЕ:Ваш метод также предполагает, что все, кто работает над вашим приложением, всегда помнит о необходимости очистки входных данных, прежде чем они попадут в базу данных, что, вероятно, в большинстве случаев нереально.
Хотя вы можете найти решение, которое работает для строк, для числовых предикатов вам также необходимо убедиться, что они передают только числа (простая проверка: можно ли их проанализировать как int/double/decimal?).
Это много дополнительной работы.
Это может сработать, но мне это кажется немного фальшивым.Я бы рекомендовал проверять корректность каждой строки, проверяя ее на соответствие регулярному выражению.
Да, можно, если...
Изучив тему, я считаю, что обработка ввода, как вы предложили, безопасна, но только при соблюдении следующих правил:
вы никогда не позволяете строковым значениям, поступающим от пользователей, становиться чем-то иным, кроме строковых литералов (т.е.избегайте указания опции конфигурации:«Введите здесь дополнительные имена/выражения столбцов SQL:»).Типы значений, отличные от строк (числа, даты,...):преобразовать их в их собственные типы данных и предоставить процедуру для литерала SQL для каждого типа данных.
- Операторы SQL проблематично проверить
вы либо используете
nvarchar
/nchar
столбцы (и префикс строковых литералов с помощьюN
) ИЛИ предельные значения, входящие вvarchar
/char
столбцы только в символы ASCII (например,выдавать исключение при создании оператора SQL)- таким образом вы избежите автоматического преобразования апострофа из CHAR(700) в CHAR(39) (и, возможно, других подобных хаков Unicode)
вы всегда проверяете длину значения, чтобы она соответствовала фактической длине столбца (если длиннее, выдайте исключение)
- в SQL Server существовал известный дефект, позволяющий обойти ошибку SQL, возникающую при усечении (приводящая к молчаливому усечению)
ты гарантируешь, что
SET QUOTED_IDENTIFIER
всегдаON
- будьте осторожны, оно вступает в силу во время анализа, т.е.даже в недоступных участках кода
Соблюдая эти 4 пункта, вы будете в безопасности.Если вы нарушите любой из них, откроется путь для SQL-инъекции.