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

StackOverflow https://stackoverflow.com/questions/139199

Вопрос

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

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

Любая одинарная кавычка, которую вводит пользователь, заменяется двойными одинарными кавычками, что исключает возможность пользователя завершать строку, поэтому все остальное, что он может ввести, например точки с запятой, знаки процента и т. д., будет частью строки, а не фактически выполняется как часть команды.Мы используем Microsoft SQL Server 2000, для которого, я считаю, одинарные кавычки являются единственным разделителем строк и единственным способом избежать разделителя строк, поэтому невозможно выполнить что-либо, что вводит пользователь.

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

ОБНОВЛЯТЬ:

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

Причина, по которой я до сих пор не принял ни одного ответа, заключается в том, что я до сих пор не знаю никакого способа эффективно запустить атаку с помощью SQL-инъекции на этот код.Несколько человек предположили, что обратная косая черта будет экранировать одну одинарную кавычку и оставить другую для завершения строки, чтобы остальная часть строки выполнялась как часть команды SQL, и я понимаю, что этот метод будет работать для внедрения SQL в база данных mySQL, но в MS SQL 2000 единственный способ (который мне удалось найти) избежать одиночной кавычки - это использовать другую одинарную кавычку;обратная косая черта этого не сделает.И если не существует способа остановить экранирование одинарной кавычки, остальная часть пользовательского ввода не будет выполнена, поскольку все они будут восприниматься как одна непрерывная строка.

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

Это было полезно?

Решение

Прежде всего, это просто плохая практика.Проверка ввода всегда необходима, но она также всегда сомнительна.
Хуже того, проверка черного списка всегда проблематична, гораздо лучше явно и строго определить, какие значения/форматы вы принимаете.Правда, это не всегда возможно – но в какой-то степени это нужно делать всегда.
Некоторые научные статьи на эту тему:

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

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

Правильный способ сделать это:

  • Проверка белого списка:тип, длина, формат или принятые значения
  • Если вы хотите внести в черный список, продолжайте.Экранирование кавычек — это хорошо, но в контексте других мер по смягчению последствий.
  • Используйте объекты команд и параметров для подготовки и проверки.
  • Вызывайте только параметризованные запросы.
  • А еще лучше использовать исключительно хранимые процедуры.
  • Избегайте использования динамического SQL и не используйте конкатенацию строк для построения запросов.
  • При использовании SP вы также можете ограничить разрешения в базе данных только для выполнения необходимых SP, а не для прямого доступа к таблицам.
  • вы также можете легко убедиться, что вся кодовая база обращается к БД только через SP...

Другие советы

Хорошо, этот ответ будет относиться к обновлению вопроса:

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

Теперь, помимо экранирования обратной косой черты MySQL - и принимая во внимание, что мы на самом деле говорим о MSSQL, на самом деле существует 3 возможных способа внедрения SQL в ваш код.

sSanitizedInput = "'" & replace(sInput, "'", "''") & "'"

Учтите, что не все они будут действительны всегда и во многом зависят от вашего фактического кода:

  1. SQL-инъекция второго порядка — если SQL-запрос перестраивается на основе данных, полученных из базы данных. после побега, данные объединяются без экранирования и могут быть косвенно внедрены с помощью SQL.Видеть
  2. Усечение строки (немного сложнее). Сценарий: у вас есть два поля, скажем, имя пользователя и пароль, и 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?).

Это много дополнительной работы.

Это может сработать, но мне это кажется немного фальшивым.Я бы рекомендовал проверять корректность каждой строки, проверяя ее на соответствие регулярному выражению.

Да, можно, если...

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

  1. вы никогда не позволяете строковым значениям, поступающим от пользователей, становиться чем-то иным, кроме строковых литералов (т.е.избегайте указания опции конфигурации:«Введите здесь дополнительные имена/выражения столбцов SQL:»).Типы значений, отличные от строк (числа, даты,...):преобразовать их в их собственные типы данных и предоставить процедуру для литерала SQL для каждого типа данных.

    • Операторы SQL проблематично проверить
  2. вы либо используете nvarchar/nchar столбцы (и префикс строковых литералов с помощью N) ИЛИ предельные значения, входящие в varchar/char столбцы только в символы ASCII (например,выдавать исключение при создании оператора SQL)

    • таким образом вы избежите автоматического преобразования апострофа из CHAR(700) в CHAR(39) (и, возможно, других подобных хаков Unicode)
  3. вы всегда проверяете длину значения, чтобы она соответствовала фактической длине столбца (если длиннее, выдайте исключение)

    • в SQL Server существовал известный дефект, позволяющий обойти ошибку SQL, возникающую при усечении (приводящая к молчаливому усечению)
  4. ты гарантируешь, что SET QUOTED_IDENTIFIER всегда ON

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

Соблюдая эти 4 пункта, вы будете в безопасности.Если вы нарушите любой из них, откроется путь для SQL-инъекции.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top