В ходе реализации нового проекта заказчик часто задаёт вопрос о том, каким образом защищена внедряемая СУБД. Один из вероятных ответов (неправильный на мой взгляд): «БД находится во внутреннем периметре вычислительной сети и недоступна для злоумышленника». По статистике инсайдеры более опасны, так как у них есть возможность легитимно исследовать уязвимости в предоставленных сервисах.
Предлагаю попробовать самостоятельно настроить уже имеющийся функционал, позволяющий повысить уровень защищённости вашей системы.
Предисловие: мне поручили задачу по написанию утилитки, которая должна проверять настройки PostgreSQL. В этой статье я хочу поделиться аналитикой возможностей данной СУБД, используемых для предотвращения несанкционированного доступа.
1. Обновление программного обеспечения.
Однозначно нужно стараться ставить последнюю версию софта или специальных патчей для закрытия обнаруженных интернет-сообществом уязвимостей. На момент написания стати это — 9.5.4. Далее мы будем изменять параметры в файле postgresql.conf из каталога PGDATA, так как все из них требуют перезапуска службы СУБД.
2. Установка нестандартных настроек.
Изменим порт подключения:
port = '5333'
Конечно nmap обнаружит сервис postgres, однако детектировать активное сканирование в сети легче, чем точечное обращение к целевому хосту. При желании можно задействовать port knocking.
3. Ограничение числа возможных подключений.
Явно указываем ip-пользователей. Пользователям не часто выдают доступ к написанию SQL-запросов, поэтому ограничиваем количество продуктивных серверов:
listen_addresses = 'ip_1, ip_2, ip_3'
Изменяем максимальное количество одновременных подключений (+1 для суперюзера или репликации). По умолчанию стоит значение 100 (видимо исходя из работы с web-сервером), но если у вас стандартная связка с пулом 1С, то устанавливаем:
max_connections = '4'
В файле pg_hba.conf убираем записи host, hostnossl и local (последний — если не используются доменные сокеты Unix). Оставляемустанавливаем только hostssl.
Убираем стандартную учётную запись postgres и параметры all: для DATABASE указываем конкретное имя БД, а для USER — имя пользователя, которому разрешено подключение.
В поле METHOD записываем тип аутентификации пользователя + дополнительные опции. В моём примере проверяем валидность пользователей по сертификатам SSL, то есть добавляем параметр cert. У нас получаются строчки вида:
hostssl test_database test_user 192.168.23.2/24 cert
Вообще здесь много свободы для фантазии, так как в postgres реализовали совместимость с GSS, SSPI, IDENT, LDAP, RADIUS и PAM.
4. Усложнение подбора пароля.
Ограниченим время для аутентификации на СУБД:
authentication_timeout = '1s'
Если не используется прямой доступ человеков, то я бы поставил значение «1s» — достаточно для ввода корректной парольной информации роботом, но недостаточно для полноценного брутфорса. Скрываем при помощи MD5 пароли пользователей PostgreSQL:
password_encryption = 'on'
Требуем, чтобы в случае успешного подключения СУБД проводила проверку доступа пользователя к БД. В случае активации этой настройки пользователей придётся создавать в формате <имя_пользователя>@<имя_рабочей_БД>.
db_user_namespace = 'on'
Если хотим использовать аутентификацию GSSAPI — устанавливаем:
krb_server_keyfile = 'файл_гсcапи'
krb_caseins_users = 'on'
Примечание: Имена становятся регистрозависимыми. При использовании этой настройки пользователям нужно создавать имена в формате <имя_пользователя>@<имя_домена>. Соответственно db_user_namespace нужно переключить в режим off.
5. Использование архитектурных особенностей.
Если у вас используется репликация, то можно ограничить количество репликантов при помощи параметров max_wal_senders = 2 и max_replication_slots = 2. Потенциальный злоумышленник даже если и получит доступ к БД, то не сможет сразу скачать все данные бэкапом при условии, что ваши реплики находятся в рабочем состоянии.
Хотя дефолтный уровень изоляции REPEATABLE READ в Postgres более строгий, чем того требует ISO/IEC 9075, тот же стандарт SQL рекомендует использовать:
default_transaction_isolation = 'serializable'
Можно задать default_transaction_read_only = on, а затем создать триггер, который будет срабатывать на изменение уровня транзакций в сессии. Таким образом можно вести журнал вносимых изменений в СУБД.
6. Шифрование канала передачи данных
Включаем ssl — защищаем КПД между PostgreSQL и клиентом:
ssl = 'on'
ssl_ciphers = 'HIGH:+3DES:!aNULL'
Параметр !aNULL запрещает вход анонимных юзеров. На всякий случай явно указываем, что наш сервер будет диктовать свои правила при установлении защищённого соединения (по дефолту так и работает):
ssl_prefer_server_ciphers = 'on'
Генерим сертификаты для SSL — можно по этой инструкции. Учитываем что Postgres требует идентичности имени выданного сертификата и имени пользователя, который производит подключение. Если используем винду, то на неё можно поставить OpenSSL и выполнять те же команды. Сертификаты по умолчанию должны находиться в PGDATA:
- сертификат нашей СУБД (без ключа):
ssl_cert_file = 'серт.crt'
- ключ для СУБД:
ssl_key_file = 'ключ.key'
- если хотим отслеживать цепочки сертификатов, то добавляем сертификат удостоверяющего центра (УЦ):
ssl_ca_file = 'ваш_са.crt'
- при активации предыдущего пункта можно отслеживать список отозванных сертификатов (СОС):
ssl_crl_file = 'ваш_сос.crl'
Перезапускаем службу postgresql, проверяем отсутствие ошибок. На стороне пользователя устанавливаем цепочку сертификатов. Проверить корректность подключения можно при помощи утилиты psql с параметрами:
psql -U test_user sslcert=test_user.crt
Вывод в случае успешного подключения:
SSL-соединение (протокол: TLSv1.2, шифр: ECDHE-RSA-AES256-GCM-SHA384, бит: 256)
Послесловие: Начиная с версии 9.5 была добавлена политика безопасности строк. Про неё и использование нативного шифрования данных в БД надеюсь у меня получиться написать отдельный текст.
Автор: postgrez4ik