Перейти к содержимому
Назад к пути
Теория 3 мин чтения

2. Фингерпринтинг СУБД

Фингерпринтинг СУБД: Определение типа базы данных

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

Для Go-разработчика этот шаг неочевиден — вы импортируете _ "github.com/lib/pq" или _ "github.com/mattn/go-sqlite3" один раз в cmd/main.go и потом просто пишете db.QueryRow(...). Тип СУБД для вас деталь инфраструктуры, не часть бизнес-логики. Атакующий же без знания типа СУБД не может правильно подобрать payload: WAITFOR DELAY '0:0:5' работает только в MSSQL, SLEEP(5) — только в MySQL, pg_sleep(5) — только в PostgreSQL. Ошибиться нельзя: неправильный синтаксис вызовет ошибку без задержки, и time-based blind не сработает.

Разберемся, какие улики помогают хакеру с точностью до версии определить вашу СУБД: PostgreSQL, MySQL или SQLite. Аналогия — врач перед операцией: ему нужно знать группу крови, аллергии, рост и вес пациента; без этого даже простая инъекция может убить. Атакующий тратит первые минуты на «диагностику» и только потом подбирает «лекарство».


1. Прямой способ: Функция version()

Самый простой и надежный метод. Хакер пробует вызвать версию БД — через UNION SELECT или error-based. Если уязвимый эндпоинт возвращает данные на фронт, хакер делает ' UNION SELECT version(), NULL, NULL-- и сразу получает строку вроде PostgreSQL 15.3 on x86_64-pc-linux-gnu. Точность вплоть до patch-версии: дальше атакующий смотрит в CVE-базу — нет ли в этой версии известных RCE.

СУБД Функция получения версии
PostgreSQL version()
MySQL @@version или version()
SQLite sqlite_version()
MS SQL Server @@version

2. Косвенный способ: Ошибки (Error-based)

Если вывод данных напрямую недоступен, хакер посылает запросы, которые вызывают ошибки. Одна и та же ошибка выглядит по-разному в зависимости от движка. Это типичная проблема Go-приложений на ранней стадии: разработчик пишет if err != nil { http.Error(w, err.Error(), 500); return } — и текст ошибки от драйвера улетает прямиком в HTTP-ответ. На staging это удобно для отладки; на production это раскрытие архитектуры базы.

  • MySQL: Table 'users' doesn't exist
  • PostgreSQL: relation "users" does not exist
  • SQLite: no such table: users

По тексту этих сообщений в логах или на странице приложения хакер сразу поймет архитектуру системы.


3. Физические различия (Конкатенация строк)

Символы объединения строк — отличный маркер типа СУБД. Хакер может проверить это через поисковую форму:

  1. ... WHERE name = 'a' || 'b' (Результат ab?) → Это PostgreSQL/SQLite
  2. ... WHERE name = CONCAT('a', 'b') (Результат ab?) → Это MySQL/PostgreSQL
  3. ... WHERE name = 'a' + 'b' (Результат ab?) → Это MS SQL Server

4. Почему это критично для хакера

Зная тип СУБД, хакер выбирает правильный "словарь" атак:

  • Для PostgreSQL будет использоваться pg_sleep().
  • Для MySQL — функция чтения файлов LOAD_FILE().
  • Для SQLite — запрос к таблице sqlite_master.

Это экономит время и позволяет избежать лишнего шума в логах — атакующий действует максимально прицельно. Вместо тысячи разноязычных payload-ов отправляются только релевантные двести-триста — снижается шанс срабатывания WAF и алертов SIEM.

Защита для Go-разработчика на этом уровне: всегда возвращать generic-ошибки клиенту (http.Error(w, "Internal server error", 500)), а оригинальный err.Error() логировать через slog/zap во внутреннюю систему. Никогда не пробрасывать строку pq.Error в HTTP-ответ — это бесплатный fingerprint для атакующего.


Идентификация цели — это залог успеха любой операции. Зная тип базы, хакер выбирает идеальный вектор эксплуатации, не тратя силы на бесполезные запросы. Это первый шаг любой профессиональной атаки — без него ни UNION SELECT, ни time-based blind не сработают на нужной СУБД.

После того как движок определен, можно приступать к масштабной выгрузке структуры всех таблиц и колонок вашей системы. И снова: единственная фундаментальная защита — параметризация (db.QueryRow(q, args...) вместо fmt.Sprintf). При корректной параметризации фингерпринтинг через инъекцию вообще невозможен — атакующий не сможет даже понять, какая СУБД крутится за бэкендом.

Продолжить чтение

Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу

Когда закончишь — отметь раздел, чтобы продолжить.

🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru