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

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

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

string userInput= "N'" + userInput.Replace("'", "''") + "'"

Аналогичный вопрос был дан ответ здесь, но я не верю, что какой - либо из ответов применимы здесь.

В SQL Server невозможно выполнить одиночную цитату с помощью "\".

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

Я не считаю, что String Truncation также является жизнеспособным вектором. SQL Server, конечно же, не будет делать усечение, так как максимальный размер для nvarchar составляет 2 ГБ в соответствии с Microsoft. Строка 2 ГБ небезопасна в большинстве ситуаций и невозможна в моей.

Вторжение второго заказа может быть возможным, но возможно ли, если:

  1. Все данные, поступающие в базу данных, дезинфицируются с использованием вышеуказанного метода
  2. Значения из базы данных никогда не добавляются в динамический SQL (почему бы вам вообще это сделать, если вы можете просто ссылаться на значение таблицы в статической части любой динамической строки SQL?).

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

Ответ 1

Есть несколько случаев, когда эта функция escape не работает. Наиболее очевидным является то, что одна кавычка не используется:

string table= "\"" + table.Replace("'", "''") + "\""
string var= "`" + var.Replace("'", "''") + "`"
string index= " " + index.Replace("'", "''") + " "
string query = "select * from `"+table+"` where name=\""+var+"\" or id="+index

В этом случае вы можете "вырваться", используя двойную кавычку, обратную отметку. В последнем случае нечего "вырываться", поэтому вы можете просто написать 1 union select password from users-- или любую полезную нагрузку sql, которую желает злоумышленник.

Следующее условие, в котором эта escape-функция завершится с ошибкой, - это если подстрока взята после того, как строка была экранирована (и да Я обнаружил такие уязвимости, как это в дикой природе):

string userPassword= userPassword.Replace("'", "''")
string userName= userInput.Replace("'", "''")
userName = substr(userName,0,10)
string query = "select * from users where name='"+userName+"' and password='"+userPassword+"'";

В этом случае имя пользователя abcdefgji' будет передано функцией abcdefgji'' функцией escape, а затем вернется в abcdefgji', взяв подстроку. Это можно использовать, установив значение пароля для любого оператора sql, в этом случае or 1=1-- будет интерпретироваться как sql, а имя пользователя будет интерпретировано как abcdefgji'' and password=. Итоговый запрос выглядит следующим образом:

select * from users where name='abcdefgji'' and password=' or 1=1-- 

T-SQL и другие усовершенствованные методы впрыска sql, которые уже упоминались. Расширенная инъекция SQL в приложениях SQL Server - отличная статья, и вы должны ее прочитать, если вы еще этого не сделали.

Последней проблемой являются атаки Unicode. Этот класс уязвимостей возникает из-за того, что функция escape не знает о кодировке с мулитным байтом, и это может быть используемое злоумышленником для "уничтожения" escape-символа. Превращение "N" в строку не поможет, так как это не влияет на значение многобайтовых символов позже в строке. Однако этот тип атаки очень необычен, потому что база данных должна быть настроена на прием строк unicode GBK (и я не уверен, что MS-SQL может это сделать).

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

Проверяйте все, ничего не верьте.

Ответ 2

С некоторыми дополнительными условиями, ваш подход выше не уязвим для SQL-инъекции. Основным вектором атаки для рассмотрения является контрабанда SQL. SQL-контрабанда возникает, когда аналогичные символы юникода переводятся неожиданным образом (например, "переходить на" ). Существует несколько мест, где стек приложений может быть уязвим для SQL-контрабанды.

  • Соответствует ли язык программирования символам юникода? Если язык не поддерживается в Юникоде, он может неправильно идентифицировать байт в символе Юникода как единую цитату и избежать ее.

  • Поддерживает ли библиотека клиентской базы данных (например, ODBC и т.д.) строки unicode? System.Data.SqlClient в .Net framework, но как насчет старых библиотек из окон 95 эпохи? Сторонние библиотеки ODBC действительно существуют. Что произойдет, если драйвер ODBC не поддерживает unicode в строке запроса?

  • Правильно ли обрабатывается БД? Современные версии SQL невосприимчивы к предположению, что вы используете N '', но как насчет SQL 6.5? SQL 7.0? Я не знаю о каких-либо особых уязвимостях, однако это не было на радаре для разработчиков в 1990-х годах.

  • Переполнение буфера? Еще одна проблема заключается в том, что цитированная строка длиннее исходной строки. В какой версии Sql Server был введен лимит 2 ГБ для ввода? До этого был предел? В более старых версиях SQL, что произошло, когда запрос превысил лимит? Существуют ли какие-либо ограничения по длине запроса с точки зрения сетевой библиотеки? Или по длине строки на языке программирования?

  • Существуют ли какие-либо языковые настройки, которые влияют на сравнение, используемое в функции Replace()?.Net всегда выполняет двоичное сравнение для функции Replace(). Так будет всегда? Что произойдет, если будущая версия .NET поддерживает переопределение этого поведения на уровне app.config? Что делать, если мы использовали regexp вместо Replace(), чтобы вставить одну цитату? Настраиваются ли настройки локали компьютера на это сравнение? Если изменение в поведении действительно произошло, оно может быть не уязвимым для SQL-инъекции, однако оно может случайно изменить строку, изменив символ уникода, который был похож на одну цитату в одну цитату, прежде чем он когда-либо достигнет БД.

Итак, предположим, что вы используете функцию System.String.Replace() в С# в текущей версии .Net со встроенной библиотекой SqlClient против текущей (SQL Server) версии SQL Server, тогда ваш подход не уязвим. Когда вы начинаете менять вещи, тогда не может быть сделано promises. Параметрированный подход запроса - это правильный подход к эффективности, производительности и (в некоторых случаях) безопасности.

ПРЕДУПРЕЖДЕНИЕ Вышеуказанные комментарии не являются подтверждением этой методики. Есть несколько других очень веских причин, почему это неправильный подход к генерации SQL. Тем не менее, детализация их выходит за рамки этого вопроса.

НЕ ИСПОЛЬЗУЙТЕ ЭТУ ТЕХНИКУ ДЛЯ НОВОГО РАЗВИТИЯ.

НЕ ИСПОЛЬЗУЙТЕ ЭТУ ТЕХНИКУ ДЛЯ НОВОГО РАЗВИТИЯ.

НЕ ИСПОЛЬЗУЙТЕ ЭТУ ТЕХНИКУ ДЛЯ НОВОГО РАЗВИТИЯ.

Ответ 3

Использование параметров запроса лучше, проще и быстрее, чем экранирование кавычек.


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

В Расширенная SQL-инъекция В приложениях SQL Server найдите слово "заменить" в тексте и с этого момента прочитайте несколько примеров где разработчики непреднамеренно допускали атаки SQL-инъекций даже после выхода из пользовательского ввода.


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

Как указывали другие, вы также можете добавлять динамический контент к вашему SQL для чего-то другого, кроме строкового литерала или литерала даты. Идентификаторы таблиц или столбцов разделяются символом " в SQL или [ ] в Microsoft/Sybase. SQL-слова, конечно, не имеют разделителей. Для этих случаев я рекомендую присваивать значения для интерполяции.

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

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

Ответ 4

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

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

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

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

Ответ 5

SQL Injection может выполняться через unicode. Если у веб-приложения есть такой URL-адрес:

http://mywebapp/widgets/?Code=ABC

который генерирует SQL как выберите * из виджетов, где Code = 'ABC'

но хакер вводит это:

http://mywebapp/widgets/?Code=ABC%CA%BC;drop виджеты таблицы -

SQL будет выглядеть так: выберите * из виджетов, где Code = 'ABC; widget widgets -'

и SQL Server будет запускать две SQL-заявки. Один, чтобы сделать выбор, и один, чтобы сделать падение. Ваш код, вероятно, преобразует URL-адрес% CA% BC с URL-адресами в unicode U02BC, который является "апострофом букв-модификаторов". Функция Replace в .Net НЕ будет рассматривать это как одну цитату. Однако Microsoft SQL Server рассматривает его как отдельную цитату. Вот пример, который, вероятно, позволит SQL Injection:

string badValue = ((char)0x02BC).ToString();
badValue = badValue + ";delete from widgets--";
string sql = "SELECT * FROM WIDGETS WHERE ID=" + badValue.Replace("'","''");
TestTheSQL(sql);

Ответ 6

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

Это не работает, если вы принимаете параметры nvarchar.

Как уже указывали другие. Самый безопасный способ - использовать параметризованный запрос.