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

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

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

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

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

экранирование одинарной кавычки с помощью " \ " невозможно в SQL Server.

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

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

Инъекция Второго Порядка может быть возможно, но возможно ли, если:

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

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

6 ответов


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

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 не знает о кодировке mulit-byte, и это может быть используется злоумышленником для "потребления" escape-символа. Добавление " N " к строке не поможет, так как это не влияет на значение многобайтовых символов позже в строке. Однако этот тип атаки очень редок, потому что база данных должна быть настроена для приема строк Юникода GBK (и я не уверен, что MS-SQL может это сделать).

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

проверьте все, не доверяйте ничему.


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

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

  • правильно ли библиотека клиентской базы данных (например, ODBC и т. д.) обрабатывает строки unicode?


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


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

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


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

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

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

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


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

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

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

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


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

http://mywebapp/widgets/?Код=ABC

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

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

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

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

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

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

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

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

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