SQL-инъекция

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

Обычно её цели включают:

  • Похищение конфиденциальных данных
  • Обход аутентификации
  • Изменение или удаление содержимого базы данных
  • Выполнение системных команд и т. д.

Как работает SQL-инъекция

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

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

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

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

Обычный запрос

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

Ниже приведён код обычного SQL-запроса:

SELECT * FROM users WHERE username = 'user1' AND password = 'password1';

Инъекционная атака

Если злоумышленник вводит:

用户名: admin' --
密码: anything

SQL-запрос становится:

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

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


Распространённые типы SQL-инъекций

1. Базовая SQL-инъекция

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

输入用户名:admin' OR '1'='1
输入密码:anything

Выполненный SQL-запрос:

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

Результат:

OR '1'='1' всегда истинно, что может позволить обойти аутентификацию.

2. Инъекция через запрос UNION

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

Вход:

' UNION SELECT null, username, password FROM users --

Выполненный SQL-запрос:

SELECT id, name FROM products WHERE id = '' UNION SELECT null, username, password FROM users --';

Результат:

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

3. SQL-инъекция на основе ошибок

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

Вход:

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

Выполненный SQL-запрос:

SELECT * FROM users WHERE username = '' AND 1=CONVERT(int, (SELECT @@version)) --';

Результат:

Сообщения об ошибках могут раскрыть версию базы данных или другую информацию.

4. Слепая SQL-инъекция

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

Слепая инъекция на основе логических выражений, ввод:

' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') --

Выполненный SQL-запрос:

SELECT * FROM users WHERE username = '' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') --';

Результат:

Определите, является ли первая буква имени базы данных 't', по возвращённому результату.

Слепая инъекция на основе времени, ввод:

' AND IF(1=1, SLEEP(5), 0) --

Выполненный SQL-запрос:

SELECT * FROM users WHERE username = '' AND IF(1=1, SLEEP(5), 0) --';

Результат:

Если условие выполняется, сервер задерживает ответ на 5 секунд, тем самым раскрывая информацию.

5. Инъекция с использованием стека запросов

Позволяет выполнять несколько SQL-запросов одновременно.

Вход:

'; DROP TABLE users; --

Выполненный SQL-запрос:

SELECT * FROM users WHERE username = ''; DROP TABLE users; --';

Результат:

Таблица users удаляется.

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

6. Инъекция через хранимые процедуры

Внедрение вредоносного SQL с использованием входных параметров хранимых процедур.

Вход:

'; EXEC xp_cmdshell('dir'); --

Выполненный SQL:

EXEC LoginProcedure 'username', ''; EXEC xp_cmdshell('dir'); --'

Результат:

Выполняет системные команды (например, вывод списка каталогов).

7. Инъекция через Cookie

Внедрение путём изменения значений Cookie, хранящихся в браузере.

Cookie: session_id=' OR '1'='1;

Сервер выполняет вредоносный SQL при разборе Cookie.


Опасности SQL-инъекции

  • Утечка данных:Злоумышленники получают из базы данных конфиденциальную информацию, такую как имена пользователей, пароли и номера банковских карт.
  • Повышение привилегий:Злоумышленники могут получить более высокие права доступа путём внедрения команд.
  • Изменение данных:Содержимое базы данных изменяется или удаляется.
  • Прерывание обслуживания:Вредоносный SQL-код может вызвать сбой базы данных, что влияет на доступность системы.
  • Выполнение системных команд:С помощью функций расширения базы данных злоумышленники могут напрямую управлять операционной системой.

Меры предотвращения

1. Параметризованные запросы и подготовленные выражения

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

Код Java:

Пример

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

Node.js (модуль MySQL):

Пример

const query = "SELECT * FROM users WHERE username = ? AND password = ?";
connection.query(query, [username, password], (err, results) => {
    if (err) throw err;
    // Обработка результатов
});

2. Использование ORM-фреймворков

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

// 使用 Sequelize
const user = await User.findOne({
    where: { username: 'admin', password: 'password123' }
});

3. Проверка входных данных

Строго проверяйте, соответствует ли ввод пользователя ожиданиям, и отклоняйте ввод, не соответствующий правилам.

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

Экранируйте специальные символы (например, преобразование " в \").

const username = req.body.username.replace(/[^a-zA-Z0-9]/g, ''); // 清理特殊字符

4. Ограничение прав доступа к базе данных

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

  • Ограничьте права на запись:Разрешайте только операции INSERT и UPDATE с соответствующими таблицами и запрещайте операции с высоким риском, такие как DROP и ALTER.
  • Разделяйте права на чтение и запись:Используйте учётную запись только для чтения для доступа к базе данных.

Создайте пользователя только для чтения:

CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'secure_password';
GRANT SELECT ON database_name.* TO 'readonly_user'@'%';

5. Регулярное тестирование безопасности

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

Для тестирования можно использовать инструмент SQLMap с открытым исходным кодом.

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

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

Другие расширения