Введение: зачем нужен аудит безопасности баз данных
База данных - это точка концентрации критичных данных компании. Логины, платёжные реквизиты, персональные данные клиентов, внутренняя аналитика. По данным исследования 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.pemMySQL 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-запросы и скрипты проверки через единый интерфейс.