1. Системные таблицы (Information Schema)
Системные таблицы: Information Schema
База данных — это не просто хранилище ваших таблиц, но и подробный справочник о самой себе. Почти любая современная СУБД содержит мета-схему information_schema, которая для хакера является «картой сокровищ». С её помощью можно узнать структуру всех таблиц и колонок, не зная их имен заранее.
Для Go-разработчика, привыкшего к db.QueryRow("SELECT name FROM products WHERE id=?", id), существование information_schema неочевидно: миграции лежат в migrations/*.sql, схема прячется в models/, и кажется, что без доступа к репозиторию никто схему не узнает. Это иллюзия. Любой драйвер database/sql — pq, mysql, sqlite3 — имеет полный read-доступ к information_schema по умолчанию, потому что эта схема нужна самим ORM (gorm, sqlx) для миграций и code-gen. Атакующий через одну SQLi получает то же самое, что ваш бэкенд-юзер.
Разберем, как устроены эти системные таблицы и как они помогают превратить слепую атаку в осознанную разведку. Аналогия — телефонный справочник в подъезде: каждая квартира помечена, фамилии видны, и грабителю не нужно ходить и стучать в каждую дверь, чтобы понять, где живёт банкир.
1. Стандарт: Information Schema
Большинство современных СУБД (PostgreSQL, MySQL, MSSQL) следуют стандарту ANSI SQL и предоставляют схему information_schema. Это «зеркальная» схема — реальные данные хранятся в системных каталогах СУБД (pg_class, mysql.tables), а information_schema — это VIEW поверх них, унифицированный по стандарту. Запретить её одной командой нельзя: эта же схема используется драйверами для introspection.
Самые важные таблицы для хакера:
information_schema.tables: Список всех таблиц в базе.information_schema.columns: Список всех колонок во всех таблицах.information_schema.routines: Хранимые процедуры и функции (полезно для эскалации до RCE черезxp_cmdshellв MSSQL илиCOPY ... FROM PROGRAMв PostgreSQL).information_schema.schemata: Список всех схем — для multi-tenant приложений где у каждого клиента своя схема.
2. Механика извлечения имен таблиц
Представьте уязвимый UNION-запрос. Хакер хочет узнать, какие таблицы есть в схеме public (PostgreSQL). Стартовый эндпоинт — обычный GET /products?category=electronics, где Go-хендлер делает fmt.Sprintf("SELECT id,name,price FROM products WHERE category='%s'", cat). Через ту же дыру в category атакующий просит у базы не товары, а собственное оглавление:
' UNION SELECT table_name, NULL, NULL FROM information_schema.tables WHERE table_schema = 'public'--
Результат: На странице вместо списка товаров появится список имен таблиц: users, products, orders, secrets_config. Типовая ошибка разработчика — назвать таблицу «по смыслу»: payment_tokens, oauth_refresh_tokens, internal_audit_log. Эти имена сразу подсказывают атакующему, куда копать дальше. Обфускация имён таблиц не защищает от SQLi — но снижает скорость разведки и даёт время WAF/SIEM засечь аномальные паттерны запросов.
3. Извлечение колонок конкретной таблицы
Как только хакер увидел таблицу users, он хочет узнать имена колонок. Здесь типовая ловушка для Go-разработчиков, использующих struct-tags из database/sql: имена колонок один-в-один совпадают с приватными полями БД (PasswordHash, OauthRefreshToken, MfaSecret). Когда атакующий читает information_schema.columns, он получает не «техническую структуру», а реальную карту бизнес-секретов, аккуратно описанных вашим же кодом.
' UNION SELECT column_name, NULL, NULL FROM information_schema.columns WHERE table_name = 'users'--
Результат: id, username, password_hash, is_admin, secret_token. Теперь хакер точно знает, по каким полям делать UNION SELECT. Никаких больше «брутфорс имён колонок» — атакующий получил готовый плейбук. Следующий запрос будет узким и точным: ' UNION SELECT username, password_hash, secret_token FROM users WHERE is_admin=true--. Если колонка is_admin имеет тип boolean, фильтр работает мгновенно и возвращает только записи с привилегиями.
Хороший защитный паттерн в Go — отделить «доменные имена» от «имён в БД» через теги: Password string \db:"pw_h"`илиgorm:"column:pw_h". Атакующий увидит pw_h, mfa_s, oauth_rt— гадать по таким сокращениям дольше, иsqlmap` без human-in-the-loop не отличит их от «технического мусора». Это не защита (параметризация — да), но дополнительный layer задержки.
4. Специфика СУБД: Если стандарта нет
Не все базы одинаковы. Если information_schema недоступна (или в SQLite её просто нет), хакеры используют специфичные для СУБД запросы. Для Go-разработчика это полезно знать в обратную сторону: какой минимальный набор привилегий выдать сервис-юзеру, чтобы атакующий не смог провести инвентаризацию. На практике — REVOKE SELECT ON information_schema.* FROM app_user в PostgreSQL не помогает (это VIEW), но REVOKE SELECT ON pg_catalog.pg_class FROM app_user ломает половину ORM-кода. Безопасность здесь — про дисциплину, не про блокировки.
| СУБД | Запрос списка таблиц |
|---|---|
| PostgreSQL | SELECT tablename FROM pg_catalog.pg_tables |
| SQLite | SELECT name FROM sqlite_master WHERE type='table' |
| Oracle | SELECT table_name FROM all_tables |
Инвентаризация данных через системные таблицы превращает хаотичные попытки в точный расчет. Если хакер умеет читать карту, он всегда найдет кратчайший путь к вашим секретам. История знает множество таких эпизодов: Yahoo Voices в 2012 году — 450 тысяч паролей выгружены через UNION SELECT из information_schema.columns, атакующий начал с пустых попыток, через 20 минут имел полную схему, через час — дамп. Heartland в 2008 году — та же техника, но через MSSQL: разведка по INFORMATION_SCHEMA.TABLES, затем выгрузка карточных треков.
Однако, чтобы разведка была успешной, хакеру сначала нужно понять, на каком «диалекте» говорит ваша база. Перейдем к процессу фингерпринтинга.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.