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:
Пример
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
Node.js (модуль MySQL):
Пример
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-инъекций.
Официальный сайт SQL:https://sqlmap.org/
-
Адрес открытого исходного кода SQLMap:https://github.com/sqlmapproject/sqlmap