Аудит безопасности баз данных: контроль привилегий и защита соединений | AdminWiki

Аудит безопасности баз данных: контроль привилегий и защита соединений

13 августа 2026 11 мин. чтения
Содержание статьи

Введение: зачем нужен аудит безопасности баз данных

База данных - это точка концентрации критичных данных компании. Логины, платёжные реквизиты, персональные данные клиентов, внутренняя аналитика. По данным исследования IBM Cost of a Data Breach 2025, средняя стоимость утечки данных выросла до 4,88 млн долларов, а доля инцидентов, связанных с неправильной конфигурацией СУБД, превысила 20%. При этом большинство атак не используют сложные эксплойты нулевого дня. Злоумышленники эксплуатируют избыточные привилегии, слабые пароли, открытые порты и отсутствие шифрования.

Аудит безопасности PostgreSQL и MySQL - это системная проверка конфигурации, прав доступа и журналов. Цель - найти и устранить уязвимости до того, как их обнаружит атакующий. В этом руководстве вы получите готовые SQL-запросы для проверки привилегий, пошаговые инструкции по включению SSL/TLS, настройке логирования и поиску типовых проблем. Материал ориентирован на администраторов баз данных и DevOps-инженеров, которые хотят провести аудит быстро и без риска для рабочей среды.

Если вы только начинаете выстраивать систему защиты, рекомендую предварительно изучить общее руководство по аудиту баз данных и практический hardening Linux-сервера, поскольку безопасность СУБД начинается с безопасности хостовой системы.

Подготовка к аудиту: что нужно знать перед началом

Перед запуском проверок выполните три обязательных шага: определите версии СУБД, создайте резервную копию и убедитесь в наличии необходимых прав. Пропуск любого из них может привести к неверным выводам или повреждению данных.

Определение версий PostgreSQL и MySQL

Версия СУБД напрямую влияет на перечень актуальных уязвимостей. Устаревшие ветки не получают патчи безопасности, и эксплуатация известных CVE становится тривиальной задачей. Проверить версию можно одним запросом.

Для PostgreSQL:

SELECT version();

Для MySQL:

SELECT VERSION();

Сравните полученную версию с последней стабильной. На август 2026 года актуальны PostgreSQL 17.x и MySQL 8.4 LTS. Если вы используете PostgreSQL 11 или MySQL 5.7, обновление - первоочередная задача, а не рекомендация. Эти ветки достигли окончания поддержки, и новые уязвимости в них не закрываются.

Для выполнения аудита нужны права суперпользователя или роли с привилегиями на чтение системных таблиц. В PostgreSQL это роль с атрибутом SUPERUSER или правами pg_read_all_settings. В MySQL - пользователь с привилегией SELECT на таблицы mysql.* и PROCESS для просмотра активных соединений. Перед любыми изменениями конфигурации создайте резервную копию: pg_dumpall для PostgreSQL и mysqldump с опцией --all-databases для MySQL.

Контроль привилегий пользователей

Избыточные привилегии - самая распространённая проблема, которую выявляет аудит. Разработчики получают SUPERUSER «на всякий случай», тестовые учётные записи не удаляются, сервисные аккаунты имеют доступ ко всем схемам. Каждая такая привилегия - потенциальная точка входа. Принцип наименьших привилегий означает: пользователь получает ровно те права, которые нужны для выполнения его задач, и ни одним больше.

Проверка ролей и привилегий в PostgreSQL

Начните с получения списка всех ролей и их атрибутов:

SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolcanlogin, rolvaliduntil
FROM pg_roles
ORDER BY rolname;

Обратите внимание на колонку rolsuper. Если значение true у ролей, которые не относятся к администраторам, это критическая находка. Атрибут rolcanlogin показывает, может ли роль использоваться для подключения. Роли с rolcanlogin = false - это группы, их компрометация менее вероятна.

Для проверки привилегий на уровне таблиц используйте information_schema:

SELECT grantee, table_schema, table_name, privilege_type
FROM information_schema.role_table_grants
WHERE grantee NOT IN ('postgres', 'pg_database_owner')
ORDER BY grantee, table_schema, table_name;

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

SELECT nspname, nspowner, nspacl
FROM pg_namespace
WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema';

Значение NULL в колонке nspacl означает, что схема доступна всем ролям с правами CREATE. Это типичная ошибка в базах, развёрнутых из шаблонов.

Проверка пользователей и прав в MySQL

В MySQL пользователи хранятся в таблице mysql.user. Первый запрос - список всех учётных записей с хостами и плагинами аутентификации:

SELECT user, host, plugin, account_locked
FROM mysql.user
ORDER BY user, host;

Колонка host критически важна. Значение '%' означает, что пользователь может подключаться с любого хоста. Для сервисных аккаунтов это допустимо только при наличии строгих сетевых ограничений. Для всех остальных - повод для немедленного исправления.

Проверьте глобальные привилегии каждого пользователя:

SHOW GRANTS FOR 'username'@'host';

Для массовой проверки выполните:

SELECT * FROM mysql.user
WHERE Super_priv = 'Y' OR Grant_priv = 'Y' OR File_priv = 'Y' OR Process_priv = 'Y';

Привилегии FILE и PROCESS часто недооценивают. FILE позволяет читать файлы сервера через LOAD_FILE(), PROCESS - просматривать чужие запросы. Обе не нужны обычным пользователям приложений.

Принцип наименьших привилегий: практические рекомендации

После выявления избыточных прав отзывайте их точечно. В PostgreSQL:

REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM app_user;
GRANT SELECT, INSERT, UPDATE ON specific_table TO app_user;

В MySQL:

REVOKE ALL PRIVILEGES ON *.* FROM 'app_user'@'%';
GRANT SELECT, INSERT, UPDATE ON appdb.* TO 'app_user'@'10.0.0.%';

Создавайте роли для типовых задач: read_only, read_write, admin. Назначайте роли пользователям вместо индивидуальных привилегий. Проводите ревизию прав ежеквартально. Удаляйте учётные записи уволенных сотрудников и неиспользуемые сервисные аккаунты в день их деактивации.

Защита соединений: настройка SSL/TLS

Без шифрования трафик между приложением и базой данных передаётся в открытом виде. Любой, кто имеет доступ к сети - соседний контейнер, скомпрометированный хост, перехватчик на уровне провайдера - может читать запросы и ответы. SSL/TLS решает эту проблему, шифруя соединение. Настройка занимает 15 минут, а эффект закрывает целый класс атак.

Включение SSL в PostgreSQL

Откройте postgresql.conf и установите параметры:

ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'

Если сертификаты ещё не созданы, сгенерируйте самоподписанный сертификат:

openssl req -new -x509 -days 365 -nodes -text -out server.crt -keyout server.key
chmod 600 server.key
chown postgres:postgres server.key server.crt

Перезапустите службу:

systemctl restart postgresql

Проверьте, что SSL активен:

SHOW ssl;

Ожидаемый вывод: on. Для принудительного шифрования всех соединений настройте pg_hba.conf, добавив hostssl вместо host для удалённых подключений. Это гарантирует, что клиенты без SSL не смогут подключиться.

Включение SSL в MySQL

В MySQL 8.0 SSL включён по умолчанию, но соединения не принудительно шифруются. Для обязательного шифрования добавьте в my.cnf:

[mysqld]
require_secure_transport = ON
ssl-ca = /etc/mysql/ca.pem
ssl-cert = /etc/mysql/server-cert.pem
ssl-key = /etc/mysql/server-key.pem

MySQL 8.0 автоматически генерирует сертификаты при инициализации, они находятся в каталоге данных. Если вы используете собственные сертификаты, укажите пути к ним. Перезапустите службу:

systemctl restart mysql

Проверьте статус:

SHOW VARIABLES LIKE 'have_ssl';
SHOW VARIABLES LIKE 'require_secure_transport';

Оба параметра должны показывать YES и ON соответственно.

Проверка шифрования соединений

Включение SSL на сервере не гарантирует, что клиенты его используют. Проверяйте активные соединения. В PostgreSQL:

SELECT pid, usename, client_addr, ssl
FROM pg_stat_ssl
JOIN pg_stat_activity USING (pid)
WHERE ssl = false AND client_addr IS NOT NULL;

Пустой результат означает, что все удалённые соединения зашифрованы. В MySQL:

SHOW STATUS LIKE 'Ssl_cipher';
SELECT * FROM performance_schema.session_status
WHERE VARIABLE_NAME = 'Ssl_cipher';

Для проверки конкретного соединения выполните в клиенте mysql команду \s и найдите строку SSL. Если там указан шифр, соединение защищено.

Анализ журналов для выявления аномальной активности

Логи - это система раннего предупреждения. Неудачные попытки входа, DDL-операции в нерабочее время, массовые SELECT из необычных подсетей - всё это видно в журналах, если логирование настроено правильно. Без логов аудит безопасности превращается в аудит конфигурации, а не реальной активности.

Настройка логирования в PostgreSQL

В postgresql.conf установите:

log_connections = on
log_disconnections = on
log_statement = 'ddl'
log_duration = off
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '

log_statement = 'ddl' фиксирует все изменения структуры: CREATE, ALTER, DROP. Это минимально необходимый уровень для аудита. Для более детального контроля используйте значение 'mod' - оно добавит INSERT, UPDATE, DELETE. Учтите, что 'mod' увеличивает объём логов в 3–5 раз. log_line_prefix добавляет временную метку, пользователя, базу и IP-адрес клиента к каждой записи.

Логи по умолчанию пишутся в /var/log/postgresql/. Для анализа используйте pgBadger - инструмент, который строит отчёты из логов PostgreSQL и показывает статистику подключений, ошибок и медленных запросов.

Настройка логирования в MySQL

В MySQL два основных журнала: general_log и slow_query_log. General log фиксирует все запросы, slow log - только медленные. Для аудита безопасности general log полезен, но сильно нагружает сервер. Включайте его только на время расследования инцидента. В my.cnf:

[mysqld]
general_log = OFF
general_log_file = /var/log/mysql/general.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_error = /var/log/mysql/error.log

Для постоянного аудита используйте error log - он фиксирует неудачные попытки входа и ошибки аутентификации. Это ключевой источник для выявления атак методом перебора паролей.

Поиск аномалий в журналах

Начните с поиска неудачных попыток входа. В PostgreSQL:

grep -i "password authentication failed" /var/log/postgresql/postgresql-*.log | awk '{print $NF}' | sort | uniq -c | sort -rn

В MySQL:

grep -i "Access denied" /var/log/mysql/error.log | awk '{print $NF}' | sort | uniq -c | sort -rn

Большое количество неудачных попыток с одного IP - признак атаки. Проверьте также DDL-операции в нерабочее время. В PostgreSQL:

grep -E "CREATE|ALTER|DROP" /var/log/postgresql/postgresql-*.log | grep -E "(0[0-5]|2[2-3]):"

Этот запрос покажет изменения структуры, выполненные между полуночью и 6 утра. Если такие операции не связаны с плановыми работами, это повод для немедленного расследования.

Поиск типовых уязвимостей

Большинство взломов баз данных происходят через типовые уязвимости, которые существуют годами. Проверьте каждый пункт из этого списка - вероятность найти хотя бы одну проблему в production-среде превышает 70%.

Проверка паролей и хостов

Пустые пароли - первая проверка. В MySQL:

SELECT user, host FROM mysql.user
WHERE authentication_string = '' OR plugin = '';

В PostgreSQL проверьте pg_hba.conf на наличие метода trust:

grep -n "trust" /etc/postgresql/*/main/pg_hba.conf

Метод trust означает аутентификацию без пароля. Он допустим только для локальных соединений в изолированных средах разработки. Для production используйте scram-sha-256 в PostgreSQL и caching_sha2_password в MySQL. Проверьте, что метод задан:

grep -n "scram-sha-256" /etc/postgresql/*/main/pg_hba.conf

Пользователи с host='%' в MySQL или адресом 0.0.0.0/0 в pg_hba.conf могут подключаться откуда угодно. Ограничьте доступ конкретными подсетями.

Обновление и патчи

Проверьте текущую версию на наличие известных уязвимостей. Для PostgreSQL используйте официальный список CVE на сайте проекта, для MySQL - базу CVE Oracle. Критичность оценивайте по CVSS: уязвимости с оценкой выше 7.0 требуют немедленного обновления. Настройте автоматические уведомления о новых патчах через подписку на security-рассылки проектов. Обновление СУБД планируйте в рамках регулярного maintenance-окна, но критические патчи применяйте вне очереди.

Открытый доступ к портам - ещё одна типовая проблема. Проверьте, что порт 5432 (PostgreSQL) или 3306 (MySQL) не доступен из интернета:

netstat -tlnp | grep -E "5432|3306"

Если порт слушает 0.0.0.0, а не 127.0.0.1 или внутренний интерфейс, это серьёзный риск. Настройте bind-address в MySQL и listen_addresses в PostgreSQL.

Автоматизация аудита безопасности

Ручной аудит - это разовая проверка. Автоматизация превращает его в непрерывный процесс. Настройте регулярные проверки, и вы будете узнавать о проблемах в день их появления, а не через полгода.

Использование pgAudit для детального аудита в PostgreSQL

pgAudit - расширение, которое пишет детальный аудит-лог в отдельный файл или в стандартный лог PostgreSQL. Установите его:

apt install postgresql-17-pgaudit

Добавьте в postgresql.conf:

shared_preload_libraries = 'pgaudit'
pgaudit.log = 'write, ddl, role'

Перезапустите PostgreSQL и создайте расширение в каждой базе:

CREATE EXTENSION IF NOT EXISTS pgaudit;

pgAudit фиксирует, кто, когда и какой запрос выполнил, включая параметры. Это закрывает требование PCI DSS о детальном аудите доступа к данным держателей карт.

MySQL Enterprise Audit и альтернативы

MySQL Enterprise Audit - плагин, доступный в коммерческой редакции MySQL Enterprise. Он предоставляет фильтруемый аудит-лог с поддержкой ротации и шифрования. Для open-source альтернативы используйте MariaDB Audit Plugin, который совместим с MySQL и доступен бесплатно. Установите его через пакетный менеджер, добавьте в my.cnf:

plugin_load_add = server_audit
server_audit_logging = ON
server_audit_events = 'CONNECT,QUERY_DDL'

Для регулярных проверок конфигурации напишите скрипт, который запускает SQL-запросы из этой статьи и сравнивает результаты с эталонными значениями. Запланируйте его выполнение через cron еженедельно. Пример для PostgreSQL:

0 3 * * 1 /usr/local/bin/db_audit.sh

Скрипт должен проверять: наличие SUPERUSER у неадминистративных ролей, пустые пароли, SSL-статус, включённое логирование. Результаты отправляйте на почту или в систему мониторинга.

Соответствие стандартам и нормативам

Аудит безопасности баз данных - прямое требование нескольких регуляторных стандартов. GDPR (ст. 32) обязывает компании обеспечивать конфиденциальность и целостность персональных данных, включая контроль доступа и шифрование. PCI DSS (требование 10) требует логирования всех операций с данными держателей карт и ежедневного анализа логов. ISO 27001 (приложение A, раздел A.12) определяет требования к управлению доступом и аудиту информационных систем.

Проведённый по этой методике аудит закрывает основные требования всех трёх стандартов: контроль привилегий соответствует принципу наименьших привилегий, SSL/TLS обеспечивает шифрование при передаче, настройка логирования даёт базу для мониторинга аномалий. Документируйте результаты каждого аудита - это необходимо для прохождения сертификационных проверок и демонстрации due diligence регуляторам.

Если вы работаете с API, которые обращаются к базе данных, дополнительно изучите руководство по аудиту безопасности API. Для комплексной оценки инфраструктуры используйте стратегию аудита IT-инфраструктуры.

Заключение: чек-лист для регулярного аудита

Аудит безопасности баз данных - это не разовое мероприятие, а регулярный процесс. Проводите его ежеквартально и после каждого значимого изменения: миграции, обновления, смены команды. Чек-лист ниже - минимальный набор проверок для PostgreSQL и MySQL.

  • Проверить версии СУБД и наличие критических CVE
  • Вывести список всех ролей и пользователей, проверить атрибуты SUPERUSER и глобальные привилегии
  • Найти учётные записи с пустыми паролями и host='%'
  • Проверить привилегии на уровне таблиц и схем, отозвать лишние
  • Убедиться, что SSL включён и все удалённые соединения зашифрованы
  • Проверить настройки логирования: log_connections, log_statement, general_log
  • Проанализировать журналы на неудачные входы и DDL в нерабочее время
  • Проверить pg_hba.conf на метод trust и открытые адреса
  • Убедиться, что порты 5432 и 3306 не доступны из интернета
  • Задокументировать результаты и план исправлений

Каждый пункт этого списка занимает от 5 до 30 минут. Полный аудит одной базы данных укладывается в 2–3 часа. Стоимость утечки данных измеряется миллионами рублей и репутационными потерями. Регулярная проверка - это страховка, которая работает.

Для размещения баз данных в изолированной облачной среде с возможностью гибкого масштабирования рассмотрите облачную инфраструктуру Timeweb Cloud. Если вы автоматизируете рутинные задачи администрирования, обратите внимание на агрегатор API нейросетей AiTunnel - он позволяет генерировать SQL-запросы и скрипты проверки через единый интерфейс.

Поделиться:
Сохранить гайд? В закладки браузера