Как проверить SQL-файл на вредоносные запросы: практическое руководство

Как проверить SQL-файл на вредоносные запросы: практическое руководство

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

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

Что искать в SQL-файле: 5 основных признаков вредоносности

Не все вредоносные запросы выглядят как DROP TABLE users;. Иногда они маскируются под полезные действия. Вот что нужно искать:

  • Создание хранимых процедур или функций — особенно с неочевидными именами вроде sp_update_cache или fn_get_session. Они могут вызываться автоматически при входе пользователя.
  • Вставка в системные таблицы — например, INSERT INTO mysql.user (MySQL) или INSERT INTO sys.sql_logins (SQL Server). Это попытка создать нового администратора.
  • Использование LOAD_FILE(), INTO OUTFILE, SELECT ... INTO DUMPFILE — эти команды позволяют читать файлы с сервера или записывать в них. Вредоносный код может записать PHP-шелл в папку с веб-контентом.
  • Запросы с EXEC, sp_executesql, sys.sp_addextendedproc — особенно если они используют динамические строки. Это классический приём для обхода ограничений.
  • Подозрительные триггеры — например, триггер на AFTER INSERT в таблицу comments, который копирует данные в другую таблицу или отправляет их на внешний URL через LOAD_FILE() или SELECT ... INTO OUTFILE.

Вот реальный пример, который я видел в одном файле:

CREATE TRIGGER backdoor AFTER INSERT ON users
FOR EACH ROW
BEGIN
  DECLARE cmd TEXT;
  SET cmd = CONCAT('SELECT * FROM users INTO OUTFILE \'/var/www/html/.config.php\'');
  PREPARE stmt FROM cmd;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END;

Этот триггер срабатывает при каждом новом пользователе и записывает все данные пользователей в PHP-файл в папке веб-сервера. После этого злоумышленник может просто открыть http://site.com/.config.php и получить доступ к базе. И всё это — в «бэкапе».

Как проверить файл: пошаговый алгоритм

Не открывай файл в блокноте и не ищи вручную. Это как искать иголку в стоге сена. Вот как делать правильно.

  1. Открой файл в текстовом редакторе с подсветкой синтаксиса — например, Notepad++ (с плагином SQL), VS Code или Sublime Text. Это поможет увидеть структуру запросов. Не используй редакторы вроде Word или Google Docs — они ломают форматирование и скрывают символы.
  2. Удали все комментарии и пустые строки — вредоносный код часто прячется за комментариями вида -- это нормальный запрос. Используй регулярное выражение: ^--.* и ^s* — удали всё, что соответствует этим шаблонам.
  3. Раздели файл на отдельные запросы — разбей его по точке с запятой. В Notepad++: Ctrl+H → найди ; → замени на ;\n. Теперь каждый запрос — на отдельной строке.
  4. Отфильтруй по ключевым словам — сделай поиск по этим словам: CREATE TRIGGER, CREATE PROCEDURE, INTO OUTFILE, LOAD_FILE, EXEC, sp_executesql, sys., mysql., INSERT INTO mysql.. Если что-то найдено — остановись. Не запускай файл.
  5. Проверь каждую найденную строку вручную — не полагайся на автоматику. Даже если запрос выглядит как «обновление кэша», посмотри: что он делает? Куда записывает? Какие таблицы трогает? Если не понимаешь — не запускай.

Если ты не уверен — не запускай. Даже если файл пришёл от «надёжного» разработчика. Доверяй, но проверяй. Это не паранойя — это стандартная практика в DevOps и безопасности.

Таблица: типичные вредоносные паттерны и их последствия

Паттерн Пример Что делает Последствия
CREATE TRIGGER ... INTO OUTFILE SELECT * FROM users INTO OUTFILE '/var/www/shell.php' Записывает данные в PHP-файл на сервере Появляется веб-шелл, злоумышленник получает полный контроль
INSERT INTO mysql.user INSERT INTO mysql.user VALUES ('hacker', 'password', 'Y', 'Y', ...) Создаёт нового пользователя с правами суперпользователя Доступ к базе даже после смены пароля администратора
CREATE PROCEDURE ... EXEC CREATE PROCEDURE p() BEGIN EXEC('cat /etc/passwd'); END; Выполняет системные команды через SQL Чтение файлов сервера, установка бэкдоров
UPDATE users SET password = ... + SELECT ... INTO DUMPFILE UPDATE users SET password = MD5('12345') WHERE id = 1; SELECT password FROM users INTO DUMPFILE '/tmp/pass.txt'; Меняет пароль админа и сохраняет его в файл Пароли украдены, доступ к панели управления
CREATE EVENT ... ON SCHEDULE CREATE EVENT e1 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO logs VALUES (NOW(), 'spam'); Автоматически запускает спам-запросы База переполнена, сервер перегружен, IP в чёрных списках

Эти паттерны — не выдумки. Я видел все пять в реальных инцидентах. Один клиент даже не заметил, что его база стала источником спама, пока не получил письмо от хостинга: «Ваш IP заблокирован за рассылку 12 000 писем в час».

Что делать, если нашёл подозрительный код?

Не удаляй его вручную. Не пытайся «починить» файл. Это как чинить бомбу — ты не знаешь, где ещё спрятаны триггеры.

Варианты:

  • Если файл — бэкап — найди альтернативный бэкап. Проверь его тем же способом. Если он чист — используй его. Если нет — восстанавливай из резервной копии, сделанной до момента компрометации.
  • Если файл — скрипт обновления — запроси у разработчика исходный код, а не SQL-файл. Пусть он выложит изменения через миграции (например, Laravel Migrations, Flyway, Liquibase). Это безопаснее.
  • Если файл — от стороннего поставщика — требуй, чтобы он предоставил не только SQL, но и описание изменений. Проверь, что каждая операция имеет логическое объяснение. Если не может — ищи другого поставщика.

Никогда не импортируй SQL-файл без предварительной проверки. Даже если он «от разработчика, который делал сайт 5 лет назад». Он мог быть скомпрометирован. Или его украл кто-то из команды.

Частые ошибки, которые приводят к катастрофе

  1. Проверяешь только SELECT-запросы — вредоносный код редко прячется в SELECT. Он в CREATE, INSERT, UPDATE, TRIGGER.
  2. Используешь «автоматические сканеры» — большинство «SQL-сканеров» не понимают триггеры, процедуры и динамические запросы. Они ищут только UNION SELECT — а это уже не актуально.
  3. Запускаешь файл в production без тестовой среды — даже если файл «чист», он может сломать структуру базы. Но если в нём есть вредоносный код — ты сразу потеряешь данные. Всегда тестируй сначала на копии базы, и только потом на проде.
  4. Полагаешься на «обязательства» разработчика — «я честный», «я не вставлял ничего лишнего». Это не аргумент. Никто не застрахован от утечки, взлома или ошибки. Проверяй сам.
  5. Не проверяешь файлы с расширением .sql, которые пришли в архиве — часто они маскируются под backup_2024.zip или update_v3.tar.gz. Проверяй каждый .sql внутри архива.

Одна из компаний, с которой я работал, потеряла 17 000 клиентских записей, потому что «разработчик сказал, что это просто обновление структуры». А внутри был триггер, который копировал email-адреса в базу на другом сервере. Сканировать он не стал — «это же не вирус».

Когда что делать: сценарии выбора

Ты не один. У тебя есть выбор. Вот как действовать в разных ситуациях.

  • Ситуация: у тебя есть доступ к исходному коду приложения — сравни SQL-файл с миграциями в репозитории. Если в репозитории нет такого запроса — он не должен быть в бэкапе. Отклоняй.
  • Ситуация: файл пришёл от внешнего подрядчика, и ты не можешь проверить его код — требуй, чтобы он предоставил: 1) описание изменений, 2) список таблиц, которые будут затронуты, 3) скриншоты или логи тестирования на стейджинге. Без этого — не запускай.
  • Ситуация: ты не знаешь, откуда файл, но нужно срочно восстановить базу — создай чистую базу, импортируй туда файл, потом экспортируй только таблицы, которые тебе нужны. Не импортируй процедуры, триггеры, события — удали их вручную. Это безопаснее, чем запускать всё подряд.
  • Ситуация: ты не можешь позволить себе остановить процесс — создай копию базы, импортируй файл туда, запусти проверку на наличие новых файлов, новых пользователей, новых триггеров. Если что-то появилось — откатись. Не рискуй продакшеном.

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

Как сделать безопаснее: рекомендации от практика

Вот что я делаю сам — и советую всем, кто работает с базами данных:

  • Всегда используй раздельные базы для теста и продакшена — даже если это одна и та же СУБД. Тестовая база — это лаборатория. Там можно экспериментировать. Продакшен — это святая святых.
  • Запрети импорт SQL-файлов через веб-интерфейс — если у тебя phpMyAdmin или Adminer — отключи возможность загрузки файлов. Используй только командную строку или скрипты с ограничениями.
  • Настрой логирование всех SQL-запросов — включай slow_query_log и general_log на тестовом сервере. Это поможет увидеть, что происходит при импорте.
  • Используй инструменты вроде SQLFluff или sqlmap (в режиме проверки) — SQLFluff проверяет синтаксис и стиль, sqlmap может найти уязвимости в запросах (но не в файлах). Это не замена ручной проверке, но помогает.
  • Проводи аудит SQL-файлов раз в квартал — даже если ты не импортировал ничего нового. Старые файлы могут содержать скрытые угрозы, которые были добавлены месяцами назад.

Если ты управляешь несколькими сайтами — заведи шаблон: «Перед импортом SQL-файла — проверка по списку из 5 пунктов». Распечатай его. Повесь на стену. Проверяй по чек-листу. Это не замедлит процесс — это предотвратит катастрофу.

Итог: что делать прямо сейчас

Если ты читаешь это — значит, у тебя есть SQL-файл, который ты собираешься запустить. Не делай этого, пока не выполнишь следующее:

  1. Открой файл в Notepad++ или VS Code.
  2. Удали все комментарии и пустые строки.
  3. Раздели запросы по точке с запятой.
  4. Найди все вхождения: CREATE TRIGGER, INTO OUTFILE, EXEC, mysql.user, LOAD_FILE.
  5. Если что-то нашёл — не запускай. Запроси у источника объяснение. Если объяснения нет — откажись от файла.
  6. Если ничего не нашёл — всё равно импортируй только в тестовую базу. Проверь, не появились ли новые пользователи, файлы, триггеры.
  7. Только после этого — на продакшен.

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

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

Оцените статью
PEFile — Безопасность и технологии простым языком