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

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

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

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

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

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

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


ОБНОВИТЬ:

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

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

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

@BryanH Признание в непонимании того, как общепринятая мудрость применима к конкретному случаю, и просьба привести пример такого конкретного случая - это не высокомерие, а скромность. С другой стороны, раздражение, когда кто-то спрашивает, почему общепринятая мудрость верна, может показаться высокомерным. Рассуждение на конкретных примерах часто является отличным способом исследовать и учиться. То, как ОП решил это сомнение, было очень полезно для моего понимания предмета, особенно когда он объяснил найденный ответ.

SantiBailors 14.06.2015 13:24

@patrik Просто наткнулся на это, поскольку я работаю над тем же фрагментом кода, но пытаюсь избежать строки и вложить запрос. Вы когда-нибудь понимали это?

3therk1ll 20.09.2019 17:26

@ 3therk1ll лучше не пробовать, лучше использовать параметризованный SQL: blog.codinghorror.com/…

Patrick 20.09.2019 19:12

@ Патрик, я подхожу к этому с точки зрения злоумышленников!

3therk1ll 20.09.2019 20:14
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
145
4
77 929
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

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

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

Это много лишней работы.

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

А как насчет экранирования кавычек в такой строке: \ '

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

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

Спасибо за ответ! Я знаю, что эта атака сработает для базы данных mySQL, но я почти уверен, что MS SQL Server не примет обратную косую черту в качестве escape-символа (я пробовал). Несколько поисков в Google не выявили никаких других escape-символов, что действительно заставило меня задуматься, почему это не сработает.

Patrick 26.09.2008 16:54

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

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

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

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

ПРИМЕЧАНИЕ. Ваш метод также предполагает, что все, кто работает с вашим приложением, всегда помнят о необходимости дезинфицировать ввод до того, как он попадет в базу данных, что, вероятно, в большинстве случаев нереально.

Проголосовано против, поскольку ответ не касается вопроса. Вопрос касается экранирования строк в SQL. Когда вы экранируете произвольную строку (как пытается сделать вопрошающий, чтобы иметь дело с необработанными данными), вы не можете просто заменить проблемные символы произвольными другими; что портит данные. (Кроме того, одинарная кавычка ЯВЛЯЕТСЯ апострофом (по крайней мере, в ASCII).)

andrewf 21.07.2016 18:02

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

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

И когда вы пропустите этот случай ОДИН на входе ОДИН, вы pwnd.

BryanH 18.11.2012 08:02

«Некоторые люди, столкнувшись с проблемой, думают:« Я знаю, я буду использовать регулярные выражения. Теперь у них две проблемы ».

MickeyfAgain_BeforeExitOfSO 05.12.2013 21:27

@mickeyf Я знаю, что это распространенное мнение, но, честно говоря, регулярные выражения довольно хороши, если вы их встретите.

tom.dietrich 07.12.2013 20:38

@ tom.dietrich Это всегда зависит от реальной жизненной ситуации. F.ex. Синтаксис regexpr нестандартен, поэтому в целом я бы не советовал использовать regexpr в контекстах, где разные системы интегрированы для совместной работы. Это связано с тем, что разные механизмы regexpr оценивают регулярные выражения по-разному, и, что более важно, этот твердый факт обычно преуменьшается или игнорируется, что может заставить разработчиков не заботиться об этих несовместимости, пока их не укусит. Таких несовместимостей предостаточно; см. например. regular-expressions.info/shorthand.html (найдите flavors на этой странице).

SantiBailors 15.06.2015 13:48

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

Что, если вам придется иметь дело с чем-то вроде "таблиц Google Fusion", где, кстати, нет какой-либо доступной библиотеки абстракций, поддерживающей его диалект? Что ты предлагаешь?

systempuntoout 17.07.2012 13:12

Вопрос не в том, что мудрее, а в том, как именно то или иное решение на самом деле терпит неудачу. Если вы не знаете, значит, у вас нет ответа на этот вопрос.

Scott Smith 04.01.2021 23:52

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

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

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

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

Вы по-прежнему можете использовать подстановку параметров, даже если вы создаете свои собственные запросы.

Nick Johnson 26.09.2008 16:57

Вы должны создать строку оператора SQL с нуля, но по-прежнему использовать подстановку параметров.

JeeBee 26.09.2008 17:01

Нет, НИКОГДА не создавайте свои операторы SQL с нуля.

AviD 27.09.2008 20:52
Ответ принят как подходящий

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

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

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

Как это сделать:

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

При правильном использовании динамический SQL и конкатенация строк можно безопасно использовать с параметризованными запросами (то есть с sp_executesql вместо EXEC). То есть вы можете динамически генерировать свой оператор SQL, если ни один из составных текстов не исходит от пользователя. Это также дает преимущества в производительности; sp_executesql поддерживает кеширование.

Brian 17.07.2010 01:34

@ Брайан, ну да ладно :). Но на самом деле, как часто вы видите, что программисты так поступают? Более того, в типичном сценарии, где «нужен» динамический SQL, требует пользовательский ввод как часть запроса (предположительно). Если бы вы могли выполнить sp_executesql, вам (обычно) вообще не понадобился бы динамический sql.

AviD 18.07.2010 19:05

В конце концов я столкнулся с ситуацией, которая заставила меня понять, что можно использовать Unicode, чтобы проскользнуть мимо замены строки. Вводимый текст был введен в Word, который изменил апостроф с прямой версии на «фигурный» апостроф (который больше похож на запятую), на который не повлияла замена строки, но который был обработан SQL как разделитель строк. Сервер. Спасибо за ответ AviD (и всем остальным)!

Patrick 31.10.2012 08:55

@AviD Я думаю, что Брайан говорит о том, что текст SqlCommand не содержит ввода непосредственно от пользователя. Вместо этого он будет содержать заполнители параметров, такие как @name, которые затем можно установить на все, что угодно, без риска инъекции. Я не считаю, что кто-то создаст что-то тупое вроде SqlCommand.Text = "EXEC(@userinput)", которое, очевидно, будет уничтожено заслуживать.

El Ronnoco 21.01.2013 16:44

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

AviD 21.01.2013 18:30

Ссылка на PDF-файл «Контрабанда SQL» теперь не работает. Можно ссылку обновить?

Eric J. 15.04.2014 22:39

@AviD Я обновил ссылку на PDF-файл о контрабанде SQL, который вы написали, до единственной версии, которую я смог найти в Интернете ... сообщите нам, есть ли другое место для вашей статьи.

Michael Fredrickson 17.12.2014 20:59

Спасибо, @MichaelFredrickson!

AviD 18.12.2014 01:34

«Вызов только параметризованных запросов»: да ... пока вы не столкнетесь с JSON_MODIFY, который ТОЛЬКО принимает строковые литералы в качестве пути. Facedesk ...

Roman Starkov 14.07.2017 17:18

Вероятно, стоит отметить, что, как правило, разумно использовать ORM, если производительность не является основной проблемой, просто убедитесь, что он хороший (т. Е. Не используйте шаблоны Active Record, используйте сопоставители данных и, ради бога, изучите и используйте базу данных боковые ограничения). Причиной этого обычно является то, что люди, которые пишут ORM, много более опытны с безопасностью SQL и, вероятно, будут получать уведомления об уязвимостях и действовать в соответствии с ними. Многие из них имеют встроенные достойные фреймворки для валидации, а также вечно полезные системы миграции.

Shayne 16.04.2019 10:02

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

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

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

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

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

Да, это должно работать до тех пор, пока кто-нибудь не запустит ВЫКЛЮЧИТЬ QUOTED_IDENTIFIER и не использует двойные кавычки для вас.

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

The SQL Server Native Client ODBC driver and SQL Server Native Client OLE DB Provider for SQL Server automatically set QUOTED_IDENTIFIER to ON when connecting. This can be configured in ODBC data sources, in ODBC connection attributes, or OLE DB connection properties. The default for SET QUOTED_IDENTIFIER is OFF for connections from DB-Library applications.

When a stored procedure is created, the SET QUOTED_IDENTIFIER and SET ANSI_NULLS settings are captured and used for subsequent invocations of that stored procedure.

SET QUOTED_IDENTIFIER also corresponds to the QUOTED_IDENTIFER setting of ALTER DATABASE.

SET QUOTED_IDENTIFIER is set at parse time. Setting at parse time means that if the SET statement is present in the batch or stored procedure, it takes effect, regardless of whether code execution actually reaches that point; and the SET statement takes effect before any statements are executed.

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

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

Patrick 21.10.2008 16:43

Ваша защита не сработает, если:

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

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

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

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

"If anyone knows of any specific way to mount a SQL injection attack against this sanitization method I would love to see it."

Теперь, помимо экранирования обратной косой черты 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. Контрабанда Unicode - В определенных ситуациях можно передать высокоуровневый символ Unicode, который выглядит похож на кавычку, но не - до тех пор, пока он не попадет в базу данных, где вдруг это. Поскольку это не цитата, когда вы ее проверяете, все пройдет легко ... Подробнее см. В моем предыдущем ответе и ссылку на исходное исследование.

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

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

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

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

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

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

После публикации я решил, что сообщение AviD освещает это более подробно. Надеюсь, мой пост еще кому-то поможет.

Jørn Jensen 19.02.2009 14:01

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

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

  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-инъекции.

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

Hogan 22.02.2016 23:52

@Hogan - Да, но я думаю, что в моем вопросе есть дополнительная ценность. У меня есть большой опыт и тестирование того, что я написал. Я знаю, что использовать параметры запроса лучше, но я также полностью понимаю ситуацию, когда кто-то должен избегать этого по разным причинам (например, работодатель требует сохранить старый способ). В этом случае я думаю, что мой ответ очень исчерпывающий и имеет большую ценность, чем ответы «только не делайте этого», потому что он указывает путь до конца. Покажите мне здесь другие ответы, которые выглядят так же, и я подумаю об удалении своего.

miroxlav 22.02.2016 23:55

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

Hogan 22.02.2016 23:59

@Hogan - У меня нет проблем с этим :) Но в настоящее время я утверждаю, что нет известного способа обойти это, если вы соблюдаете 4 правила, которые я опубликовал. Если вы действительно думаете, что есть способ обойти это, просто укажите где.

miroxlav 23.02.2016 00:24

Плохой совет hombre. Интерполяция Любые может быть отклонена.

Shayne 16.04.2019 10:07

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

miroxlav 16.04.2019 15:51

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