РАЗБОР
Статья
Аутентификация: приложение vs СУБД - разбор атак
[ обложка статьи ]
Режим чтения
Понедельник, 9:15 утра. На SOC-дашборде - алерт: нетипичный объём SELECT-запросов к таблице
payments из одного микросервиса. Разбираем - и картина знакомая до боли: атакующий через SSRF вытащил connection string из переменной окружения, подключился к PostgreSQL напрямую и за 12 минут выгрузил 40 тысяч записей. Приложение аккуратно проверяло JWT на каждый API-вызов, но база видела только один service account с правами на все таблицы. Один. На всё.Этот разрыв между аутентификацией на уровне приложения и встроенной аутентификацией СУБД стоил компании утечки персональных данных с перспективой оборотного штрафа. И он повторяется в каждом втором аудите, где архитектура строилась по принципу "приложение знает, кто пользователь, а база - нет".
Две модели аутентификации: архитектурные различия
Аутентификация на уровне приложения
Здесь приложение берёт на себя всю логику аутентификации и авторизации. Пользователь проходит проверку через OAuth 2.0, JWT-токен или сессионный cookie. Приложение валидирует identity, определяет доступ - через RBAC-middleware, policy engine или ORM-фильтры. К СУБД приложение подключается через единый service account (или пул) с постоянным набором привилегий. Подробнее - в нашем статье о атаки на аутентификацию.Поток: пользователь проходит JWT-валидацию → middleware проверяет роли -> запрос уходит через connection pool в СУБД от имени service account с широкими привилегиями.
Что из этого следует:
- Вся логика авторизации живёт в коде приложения. СУБД не различает конечных пользователей - видит только service account.
- Масштабирование через connection pooling (PgBouncer, HikariCP) работает просто: все соединения идут от одного пользователя.
- Аудит на уровне СУБД показывает только действия service account. Реальный пользователь - только в логах приложения. И если логи приложения не пишутся или ротируются раз в сутки - удачи в расследовании.
- По OWASP API Security Top 10, API-трафик часто несёт чувствительные токены через потенциально недоверенные сети, и именно application-level auth отвечает за проверку каждого запроса.
Встроенная аутентификация СУБД
Здесь каждый пользователь (или группа) имеет собственную учётную запись в СУБД. Аутентификация проходит через встроенные механизмы: парольная проверка (scram-sha-256 в PostgreSQL), Kerberos/GSSAPI, LDAP, клиентские сертификаты или PAM. Авторизация - через GRANT/REVOKE, роли и Row-Level Security (RLS).Поток: приложение передаёт credentials пользователя -> СУБД аутентифицирует через
pg_hba.conf -> применяет GRANT/REVOKE и RLS к каждому запросу.Что даёт эта модель:
- СУБД знает, кто конкретно выполняет запрос. Аудит через pgAudit (PostgreSQL), SQL Server Audit или MySQL Enterprise Audit привязан к реальному пользователю - не к безликому
app_service. - Привилегии гранулярны - до уровня столбца или строки через RLS.
- Connection pooling усложняется: каждому пользователю нужно своё соединение или механизм
SET ROLEпри смене контекста. Тут начинается боль. - Интеграция с доменной инфраструктурой (Active Directory, FreeIPA) через Kerberos позволяет строить единый SSO-контур. Этот подход описан и в документации СУБД Jatoba, и рекомендован PostgreSQL STIG.
Сравнение методов аутентификации: модели контроля доступа СУБД
| Критерий | Application-level | Database-native | Когда НЕ подходит |
|---|---|---|---|
| Гранулярность авторизации | RBAC/ABAC в middleware | GRANT/REVOKE + RLS до строки/столбца | App-level - когда нужен аудит per-user на уровне БД |
| Аудит: кто выполнил запрос | Service account (пользователь - только в логах приложения) | Реальный пользователь через pgAudit | DB-native - при тысячах пользователей аудит генерирует терабайты логов |
| Масштабируемость | Высокая, connection pooling без ограничений | Ограничена числом соединений | DB-native - в микросервисах с горизонтальным масштабированием |
| Устойчивость к обходу приложения | Низкая: обход = полный доступ | Высокая: привилегии роли действуют всегда | App-level - при SSRF/прямом доступе к порту СУБД |
| Совместимость с микросервисами | Нативная | Требует Kerberos delegation или credential forwarding | DB-native - в Kubernetes с ephemeral pods |
| Insider threat visibility | Зависит от логирования приложения | Нативный аудит на уровне СУБД | App-level - при расследовании инцидента без корреляции логов |
| Сложность внедрения | Средняя (зависит от IAM-стека) | Высокая (синхронизация ролей, pg_hba.conf) | DB-native - в командах без DBA-экспертизы |
Это не бинарный выбор. В зрелых архитектурах комбинируют оба подхода: приложение аутентифицирует пользователя и выполняет
SET ROLE в рамках сессии СУБД, сохраняя гранулярность database-level привилегий при connection pooling. Но до такой зрелости доживают не все.Уязвимости аутентификации базы данных: поверхность атаки и TTPs
Обход SQL injection аутентификации
При application-level auth SQL-инъекция в запросе авторизации может полностью обойти проверку прав. Классика - запросSELECT * FROM users WHERE login='...' AND pass='...', куда атакующий подставляет ' OR 1=1 --. Если приложение строит запросы конкатенацией вместо параметризованных выражений, аутентификация обходится за один HTTP-запрос. Один.По классификации OWASP это попадает одновременно под A07:2021 - Identification and Authentication Failures и A01:2021 - Broken Access Control (94% приложений тестировались на ту или иную форму broken access control).
При database-native auth SQL-инъекция не обходит аутентификацию СУБД - атакующий уже аутентифицирован через
pg_hba.conf или Kerberos-тикет. Но инъекция может привести к повышению привилегий: выполнение ALTER ROLE или вызов привилегированной функции от имени текущей роли при неаккуратных GRANT. Тут уже другая головная боль.Privilege escalation через базу данных
Бизнес-логика атаки: злоумышленник получает начальный доступ к СУБД и стремится расширить привилегии для выгрузки чувствительных таблиц или выполнения команд ОС. Зачем? Продажа выгруженных данных, шифрование для выкупа, либо использование скомпрометированного сервера как плацдарма для lateral movement. Мотивация простая - деньги или доступ к следующей цели.Типичные сценарии по каждой модели:
Application-level модель:
Утечка connection string из конфигов, переменных окружения или логов - техника Credentials In Files (T1552.001, Credential Access). Даёт полные привилегии service account. На практике connection string валяется в
.env, docker-compose.yml, а иногда и в git-истории. Service account с SUPERUSER или избыточными GRANT - мисконфигурация, соответствующая OWASP A05:2021 - Security Misconfiguration. SSRF до порта СУБД - Exploit Public-Facing Application (T1190, Initial Access). Если сетевой доступ к порту 5432/3306/1433 не ограничен, атакующий подключается напрямую.Database-native модель:
Password Spraying (T1110.003, Credential Access) по открытому порту СУБД при слабой парольной политике - банально, но до сих пор работает. Бэкдор в PAM-модуле - Pluggable Authentication Modules (T1556.003, Persistence + Credential Access). Атакующий модифицирует цепочку PAM для перехвата паролей и поддержания доступа. Использование Valid Accounts (T1078, Initial Access + Privilege Escalation) - скомпрометированный сотрудник или оставленная учётная запись уволенного (привет, offboarding-процессы). Модификация процесса аутентификации (T1556, Defense Evasion + Persistence) - подмена конфигурации
pg_hba.conf для добавления trust-доступа с произвольного IP.| MITRE ATT&CK | Тактика | Application-level | Database-native |
|---|---|---|---|
| T1190 - Exploit Public-Facing Application | Initial Access | SSRF до connection string | Прямая эксплуатация открытого порта СУБД |
| T1110.003 - Password Spraying | Credential Access | Перебор через API приложения | Перебор учётных записей СУБД |
| T1078 - Valid Accounts | Persistence, Priv Esc | Компрометация service account | Компрометация DBA-аккаунта |
| T1552.001 - Credentials In Files | Credential Access | Connection string в .env, docker-compose | Пароли в .pgpass, my.cnf |
| T1556.003 - Pluggable Auth Modules | Persistence | Неприменимо | Бэкдор в PAM-цепочке |
| T1556 - Modify Authentication Process | Credential Access | Подмена JWT-секрета | Модификация pg_hba.conf |
Detection: правила корреляции для SOC
Аномалии в application-level модели
Основная сложность: все запросы идут от service account, поэтому корреляцию нужно строить на стыке логов приложения и СУБД. Два источника, которые нужно склеить - и у каждого свой формат, свой timestamp, своя ротация.Что мониторить и на что ставить алерты:
- Всплеск запросов к чувствительным таблицам. Baseline: средний объём SELECT за 15-минутный интервал. Алерт при отклонении >3 сигма. Если за 5 минут от одного source IP приходит >100 SELECT к таблице с PII при baseline <10 - это аномалия.
- Запросы к таблицам, которые конкретный микросервис не трогает. Требует корреляции application logs (service name) с DB audit (table name). Каждый микросервис должен иметь задокументированный перечень используемых таблиц. Да, это значит - документация. Да, её никто не любит писать.
- Прямые подключения мимо connection pool. Алерт: source IP подключения к СУБД не совпадает ни с одним IP из пула серверов приложения. Если кто-то подключился с IP, которого нет в whitelist - это либо инцидент, либо DBA забыл предупредить.
- Изменение connection string в runtime. Мониторинг через EDR на хостах приложения - отслеживание изменений в переменных окружения и конфигурационных файлах.
Аномалии во встроенной аутентификации СУБД
Аудит здесь гранулярнее - каждый запрос привязан к реальному пользователю. Но нужно настроить pgAudit:
SQL:
-- pgAudit: включение логирования DDL и role-операций
ALTER SYSTEM SET pgaudit.log = 'ddl, role';
ALTER SYSTEM SET pgaudit.log_parameter = on;
SELECT pg_reload_conf();
- Auth failures. Порог: >5 неуспешных попыток аутентификации от одного источника за 10 минут - detection для Brute Force (T1110). Казалось бы, очевидно. Но я регулярно вижу конфигурации, где этот алерт просто не настроен.
- Логин DBA-роли в нерабочее время или с нетипичного IP-адреса. Требует базового baseline по времени и гео.
- DDL-команды от неожиданных ролей. Выполнение
ALTER ROLE,GRANT,CREATE EXTENSIONне из утверждённого IP-диапазона. - Изменения
pg_hba.confи перезагрузка конфигурации черезpg_reload_conf()- мониторинг через file integrity monitoring.
Insider threat: что видно в каждой модели
В application-level модели инсайдер-разработчик с доступом к connection string получает полные привилегии service account. Отследить его действия можно только если приложение записывает user ID в каждый SQL-запрос - черезSET app.current_user или comment-based audit trail. На практике это реализуют единицы. Остальные узнают о проблеме на постинцидентном разборе.В database-native модели действия инсайдера привязаны к его персональной роли. pgAudit фиксирует каждый запрос с username. При incident response не нужно коррелировать логи трёх систем - аудит СУБД сразу показывает, кто выгрузил таблицу, когда и откуда. Для постинцидентного разбора это преимущество, которое сложно переоценить.
Hardening: безопасность доступа к базам данных
Отдельная тема - connection pooling и безопасность. PgBouncer в режиме
transaction не поддерживает SET ROLE без дополнительных workaround. Варианты: переход в режим session (с потерей производительности) или использование auth_query + server_reset_query для передачи контекста пользователя. Этот trade-off нужно закладывать на этапе проектирования архитектуры аутентификации СУБД, а не когда прилетел инцидент и всё горит.Опыт последних двух лет показывает устойчивую закономерность: команды, которые строят защиту только на одном слое - только application-level или только database-native - проигрывают при первом серьёзном инциденте. Application-level auth отлично масштабируется и интегрируется с OAuth/OIDC, но создаёт single point of failure в виде service account. Встроенная аутентификация СУБД даёт гранулярный аудит и реальный defense in depth, но усложняет DevOps-процессы и требует DBA-экспертизы, которой у большинства команд просто нет.
На постинцидентных разборах я вижу одну и ту же ошибку: команда выбирает "или-или" и строит модель угроз вокруг одного слоя. Атакующий находит путь через другой. SSRF до базы обходит JWT. Компрометация PAM-модуля обходит GRANT/REVOKE. Единственная рабочая стратегия - layered auth, где приложение проверяет identity и передаёт контекст в СУБД через
SET ROLE, а СУБД дополнительно ограничивает доступ через RBAC и RLS. Это заметно сложнее в реализации - но именно такая связка выдерживает реальные атаки, а не только compliance-аудиты. На codeby.net есть тред, где разбираем конфиги pg_hba.conf и pgAudit под разные архитектуры - если настраиваешь подобную связку, стоит заглянуть.
AI-выжимка
по разделам
Тезисы статьи скоро
Статья читается полностью. Тезисы со ссылками на разделы появятся позже.
Содержание
Codeby Academy
Практика и мастерство
От основ до продвинутого — программы для практиков Codeby.
Перейти к курсу →
Продолжить чтение
Следующий разбор
UX в аутентификации: passwordless и MFA на практике
Комментарии
0