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

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

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

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

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

обновление:

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

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

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

18 ответов


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

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

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

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

  • проверка белого списка: Тип, длина, формат или принято значения
  • если вы хотите черный, то вперед. Цитата escaping хороша, но в контексте других смягчений.
  • используйте объекты Command и Parameter для подготовки и проверки
  • вызывать только параметризованные запросы.
  • еще лучше, используйте хранимые процедуры исключительно.
  • избегайте использования динамического SQL, и не используйте конкатенацию строк для построения запросов.
  • при использовании SPs вы также можете ограничить разрешения в базе данных выполнение только необходимых SPs, а не доступ к таблицам напрямую.
  • вы также можете легко проверить, что вся кодовая база обращается только к БД через SPs...

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

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

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

sSanitizedInput ="'" & Заменить(sInput, "'", """) & "'"

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

  1. SQL-инъекция второго порядка - если SQL-запрос перестраивается на основе данных, полученных из базы данных после побега, данные объединяются без эскапады и могут быть косвенно введены SQL. См.
  2. усечение строки - (немного сложнее) - сценарий-это вы есть два поля, скажем, имя пользователя и пароль, и SQL объединяет их обоих. И оба поля (или только первое) имеют жесткий предел длины. Например, имя пользователя ограничено 20 символами. Скажем, у вас есть этот код:
username = left(Replace(sInput, "'", "''"), 20)

то, что вы получаете - это имя пользователя, бежал, а потом обрезается до 20 символов. Проблема здесь - я вставлю свою цитату в 20-й символ (например, после 19 a), и ваша бегущая цитата будет обрезана (в 21-й персонаж). Затем в SQL

sSQL = "select * from USERS where username = '" + username + "'  and password = '" + password + "'"

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


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


Я понимаю, что это долгое время после того, как вопрос был задан, но ..

один из способов начать атаку на процедуру "цитировать аргумент" - это усечение строки. Согласно MSDN, в SQL Server 2000 SP4 (и SQL Server 2005 SP1) слишком длинная строка будет тихо усечена.

когда вы цитируете строку, строка увеличивается в размере. Каждый Апостроф повторяется. Затем это можно использовать для выталкивания частей SQL за пределы буфера. Так вы смогли эффектно обрезать части предложения where.

Это, вероятно, будет в основном полезно в сценарии страницы "user admin", где вы можете злоупотреблять инструкцией "update", чтобы не выполнять все проверки, которые он должен был делать.

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

Я бы рекомендовал пойти с параметрами. Всегда. Жаль, что я не могу внедрить это в базу данных. И в качестве побочного эффекта вы, скорее всего, получите лучшие хиты кэша, потому что больше операторов выглядят одинаково. (Это, безусловно, верно для Oracle 8)


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


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

сам по себе он безопасен AFAIK. Однако, как указал другой ответчик, вам также может потребоваться иметь дело с backspace экранирование (хотя и не при передаче запроса SQL Server с помощью ADO или ADO.NET по крайней мере -- не могу поручиться за все базы данных или технологии).

загвоздка в том, что вы действительно должны быть уверены, какие строки содержат пользовательский ввод (всегда потенциально вредоносный), и какие строки являются допустимыми SQL-запросами. Одна из ловушек - если вы используете значения из базы данных-были ли эти значения изначально предоставлены пользователем? Если это так,то они тоже должны быть спасены. Мой ответ - попытаться санировать как можно позже. возможно (но не позже!), при построении SQL-запроса.

однако в большинстве случаев привязка параметров-это путь - это просто проще.


Это плохая идея, как вам кажется, знаете.

Как насчет чего-то вроде избежания цитаты в строке, как это: \'

ваша замена приведет к: \"

Если обратная косая черта избегает первой цитаты, то вторая цитата завершила строку.


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

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

приличная запись здесь:http://www.owasp.org/index.php/Top_10_2007-A2

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


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


Если у вас есть параметризованные запросы, вы должны использовать их в любое время. Все, что требуется для одного запроса, чтобы проскользнуть через сеть, и ваша БД находится под угрозой.


Да, это должно работать до тех пор, пока кто-то не побежит УСТАНОВИТЬ QUOTED_IDENTIFIER OFF и использует двойную цитату на вас.

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

драйвер ODBC собственного клиента SQL Server и поставщик OLE DB собственного клиента SQL Server для SQL Server автоматически устанавливают QUOTED_IDENTIFIER в ON при подключении. Это можно настроить в источниках данных ODBC, в соединении ODBC атрибуты или свойства подключения OLE DB. значение по умолчанию для SET QUOTED_IDENTIFIER отключено для соединений из приложений DB-Library.

при создании хранимой процедуры SET QUOTED_IDENTIFIER и SET ansi_nulls параметры захватываются и используются для последующих вызовов этой хранимой процедуры.

установить QUOTED_IDENTIFIER также соответствует параметру QUOTED_IDENTIFER базы данных ALTER.

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

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


ваша защита потерпит неудачу, если:

  • запрос ожидает число, а не строку
  • был любой другой способ представить одинарную кавычку, включая:
    • escape-последовательность, такая как \039
    • символ Unicode

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


Патрик, вы добавляете одинарные кавычки вокруг всех входных данных, даже числовых? Если у вас есть числовой ввод, но вы не ставите вокруг него одинарные кавычки, у вас есть экспозиция.


какой уродливый код все, что дезинфекция пользовательского ввода будет! Затем неуклюжий StringBuilder для оператора SQL. Подготовленный метод оператора приводит к гораздо более чистому коду, а преимущества SQL-инъекции-действительно приятное дополнение.

и зачем изобретать велосипед?


вместо того, чтобы изменять одну цитату на (что похоже) две одиночные кавычки, почему бы просто не изменить ее на Апостроф, цитату или удалить ее полностью?

в любом случае, это немного kludge... особенно, когда у вас есть законные вещи (например, имена), которые могут использовать одинарные кавычки...

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


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


хотя вы можете найти решение, которое работает для строк, для числовых предикатов вам также нужно убедиться, что они проходят только в числах (простая проверка может быть проанализирована как int/double/decimal?).

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


Да, вы можете, если...

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

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

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

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

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

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

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