Перейти к содержанию

Что такое SQL-инъекция (SQLi)?

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

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

Последствия успешной атаки с использованием SQL-инъекции?

Успешная атака с использованием SQL-инъекции может привести к несанкционированному доступу к конфиденциальным данным, таким как:

  • Пароли.
  • Данные кредитной карты.
  • Личная информация пользователя.

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

Как обнаружить уязвимости SQL-инъекций

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

  • Символ одинарной кавычки ' и ищите ошибки или другие аномалии.
  • Некоторый специфичный для SQL синтаксис, который вычисляет базовое (исходное) значение точки входа и другое значение и ищет систематические различия в ответах приложения.
  • Логические условия, такие как OR 1=1 и OR 1=2, и ищите различия в ответах приложения.
  • Полезные нагрузки, предназначенные для запуска временных задержек при выполнении SQL-запроса и поиска различий во времени, затрачиваемом на ответ.
  • Полезные нагрузки OAST предназначены для запуска внеполосного сетевого взаимодействия при выполнении в рамках SQL-запроса и мониторинга любых результирующих взаимодействий.

SQL-инъекция в разных частях запроса

Большинство уязвимостей SQL-инъекции возникают в предложении WHERE запроса SELECT. Большинство опытных тестировщиков знакомы с этим типом SQL-инъекции.

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

  • В инструкциях UPDATE, внутри обновленных значений или предложения WHERE.
  • В инструкциях INSERT, внутри вставленных значений.
  • В инструкциях SELECT, внутри имени таблицы или столбца.
  • В операторах SELECT, в предложении ORDER BY.

Примеры ситуаций SQL-инъекций

Существует множество уязвимостей, атак и техник SQL-инъекций, которые возникают в различных ситуациях.

Некоторые распространенные примеры SQL-инъекций включают:

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

Извлечение скрытых данных

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

https://example.com/products?category=Gifts

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

SELECT * FROM products WHERE category = 'Gifts' AND released = 1

Этот SQL-запрос запрашивает у базы данных:

  • все сведения (*)
  • из таблицы товаров products
  • где категория, подарки Gifts
  • и которые выпущены released = 1.

Ограничение released = 1 используется для скрытия продуктов, которые еще не выпущены. Мы могли бы предположить, что для неизданных продуктов значение released = 0.

Приложение не реализует никаких средств защиты от атак с использованием SQL-инъекций. Это означает, что злоумышленник может сконструировать следующую атаку, например:

https://example.ru/products?category=Gifts '--

Это приводит к выполнению SQL-запроса:

SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1

Важно отметить, что -- - это индикатор комментариев в SQL. Это означает, что остальная часть запроса интерпретируется как комментарий, фактически удаляя его. В данном примере это означает, что запрос больше не включает and released = 1. В результате отображаются все продукты, включая те, которые еще не выпущены.

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

https://example.ru/products?category=Gifts'+OR+1=1--

Это приводит к выполнению SQL-запроса:

SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1

Измененный запрос возвращает все элементы, в которых либо category это Gifts, либо 1 равно 1. Поскольку 1=1 всегда равно true, запрос возвращает все элементы.

Предупреждение

Будьте осторожны при вводе условия OR 1=1 в SQL-запрос. Даже если это кажется безвредным в контексте, в который вы вводите, приложения обычно используют данные из одного запроса в нескольких разных запросах. Например, если ваше условие достигнет инструкции UPDATE или DELETE, это может привести к случайной потере данных.

Подмена авторизационных данных

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

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'

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

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

SELECT * FROM users WHERE username = 'administrator'--' AND password = ''

Этот запрос возвращает пользователя, чье имя username является administrator, и успешно регистрирует злоумышленника как этого пользователя.

Извлечение данных из других таблиц базы данных

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

Например, если приложение выполняет следующий запрос, содержащий введенные пользователем данные Gifts:

SELECT name, description FROM products WHERE category = 'Gifts'

Злоумышленник может отправить вводимые данные:

' UNION SELECT username, password FROM users--

Это приведёт к тому, что приложение вернет все имена пользователей и пароли вместе с названиями и описаниями продуктов.

Слепые SQL-инъекции

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

Следующие методы могут быть использованы для использования уязвимостей, связанных с внедрением SQL вслепую, в зависимости от характера уязвимости и используемой базы данных:

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

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

  • Вы можете инициировать внеполосное сетевое взаимодействие, используя методы OAST. Эта техника чрезвычайно эффективна и работает в ситуациях, когда другие техники этого не делают. Часто вы можете напрямую отфильтровать данные по внеполосному каналу. Например, вы можете поместить данные в поисковую систему DNS для домена, который вы контролируете.

SQL-инъекция второго порядка

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

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

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

Изучение базы данных

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

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

Например:

  • Синтаксис для объединения строк.
  • Комментарии.
  • Пакетные (или штабелированные) запросы.
  • API-интерфейсы, зависящие от платформы.
  • Сообщения об ошибках.

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

Вы можете запросить сведения о версии базы данных. Разные методы работают для разных типов баз данных. Это означает, что если вы найдете конкретный метод, который работает, вы можете определить тип базы данных. Например, в Oracle вы можете выполнить:

SELECT * FROM v$version

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

SELECT * FROM information_schema.tables

SQL-инъекция в разном контексте

Вы можете выполнять атаки с использованием SQL-инъекций, используя любой управляемый ввод, который обрабатывается приложением как SQL-запрос. Например, некоторые веб-сайты принимают входные данные в формате JSON или XML и используют их для запроса к базе данных.

Эти различные форматы могут предоставить вам различные способы запутывания атак, которые в противном случае блокируются из-за WAFS и других механизмов защиты. Слабые реализации часто ищут в запросе распространенные ключевые слова для SQL-инъекций, поэтому вы можете обойти эти фильтры, закодировав или экранируя символы в запрещенных ключевых словах. Например, следующая SQL-инъекция на основе XML использует управляющую последовательность XML для кодирования символа S в SELECT:

<payCheck>
    <productId>123</productId>
    <payId>999 &#x53;ELECT * FROM information_schema.tables</payId>
</payCheck>

Это будет декодировано на стороне сервера перед передачей интерпретатору SQL.

Как предотвратить SQL-инъекцию

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

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

String query = "SELECT * FROM products WHERE category = '"+ input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);

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

PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();

Вы можете использовать параметризованные запросы для любой ситуации, когда ненадежные входные данные отображаются в виде данных внутри запроса, включая предложение WHERE и значения в инструкции INSERT или UPDATE. Они не могут быть использованы для обработки ненадежных входных данных в других частях запроса, таких как имена таблиц или столбцов, или предложение ORDER BY. Функциональность приложения, которое помещает ненадежные данные в эти части запроса, должна использовать другой подход, например:

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

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