Как обезопасить открытый порт PostgreSQL

Итак, это ситуация. Кажется, нам нужен открытый TCP-порт 5432 для мира, где клиент имеет доступ к своей базе данных PostgreSQL.

По понятным причинам мы не можем просто сказать "нет", только как последнее средство.

Какие самые большие проблемы? Как я могу защитить нашу инфраструктуру?

В любом случае: почему это не должно быть открыто миру? Я думаю, может быть, это более безопасно, чем какой-то 20-летний необслуживаемый FTP-сервер.

PS VPN не в порядке. Может быть, какое-то шифрование (если я могу дать ему URL соединения JDBC, который работает).

5 ответов

Решение

Требовать SSL, держать SELinux включенным, отслеживать журналы и использовать текущую версию PostgreSQL.

Серверная сторона

Требовать SSL

В postgresql.conf задавать ssl=on и убедитесь, что ваш ключевой файл и файл сертификата установлены правильно (см. документацию и комментарии в postgresql.conf).

Вам может потребоваться купить сертификат в ЦС, если вы хотите, чтобы клиенты доверяли ему без специальной настройки на клиенте.

В pg_hba.conf использовать что-то вроде:

hostssl theuser thedatabase 1.2.3.4/32 md5

... возможно с "all" для пользователя и / или базы данных, и, возможно, с более широким фильтром IP-адресов источника.

Ограничение пользователей, которые могут войти, запретить удаленный вход суперпользователя

Не допускайте "все" для пользователей, если это возможно; Вы не хотите разрешать входы суперпользователя удаленно, если можете избежать этого.

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

Ограничьте права пользователей, которые могут войти в систему. Не давайте им CREATEDB или же CREATEUSER прав.

REVOKE CONNECT прямо из PUBLIC во всех ваших базах данных, затем отдайте его только тем пользователям / ролям, которые должны иметь доступ к этой базе данных. (Группируйте пользователей по ролям и предоставляйте права на роли, а не напрямую отдельным пользователям).

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

Настройка клиента

В PgJDBC передайте параметр ssl=true:

Чтобы указать драйверу JDBC попытаться установить соединение SSL, необходимо добавить параметр URL-адреса соединения ssl = true.

... и установите сертификат сервера в хранилище доверенных сертификатов клиента или используйте сертификат сервера, которому доверяет один из ЦС, во встроенном хранилище доверенных сертификатов Java, если вы не хотите, чтобы пользователь устанавливал сертификат.

Текущие действия

Теперь убедитесь, что вы поддерживаете PostgreSQL в актуальном состоянии. В PostgreSQL было только несколько дыр в безопасности перед авторизацией, но это больше нуля, так что будьте в курсе. В любом случае, вы должны исправлять ошибки.

Добавьте брандмауэр впереди, если есть большие сетевые блоки / регионы, к которым вам не нужен доступ.

Журнал подключений и отключений (см. postgresql.conf). Журнал запросов, если это возможно. Запустите систему обнаружения вторжений или fail2ban или аналогичную, если это возможно. Для fail2ban с postgres есть удобная инструкция

Контролировать файлы журнала.

Бонус паранойи

Дополнительные шаги, чтобы думать о...

Требовать клиентские сертификаты

Если вы хотите, вы также можете использовать pg_hba.conf требовать, чтобы клиент представил сертификат клиента X.509, которому доверяет сервер. Для этого не нужно использовать тот же CA, что и для сертификата сервера, вы можете сделать это с помощью CA Homebrew openssl. Пользователь JDBC должен импортировать сертификат клиента в свое хранилище ключей Java с keytool и, возможно, настроить некоторые системные свойства JSSE для указания Java на их хранилище ключей, чтобы оно не было полностью прозрачным.

Изолировать экземпляр

Если вы хотите быть действительно параноиком, запустите экземпляр для клиента в отдельном контейнере / виртуальной машине или, по крайней мере, под другой учетной записью пользователя, используя только те базы данных, которые им необходимы.

Таким образом, если они скомпрометируют экземпляр PostgreSQL, они больше не получат.

Используйте SELinux

Я не должен был говорить это, но...

Запустите компьютер с поддержкой SELinux, например RHEL 6 или 7, и не выключайте SELinux и не устанавливайте его в разрешающий режим. Держите это в принудительном режиме.

Использовать порт не по умолчанию

Безопасность только мраком - это глупость. Безопасность, которая использует немного неясности после того, как вы сделали разумные вещи, вероятно, не повредит.

Запустите Pg на порте не по умолчанию, чтобы немного усложнить жизнь автоматизированным злоумышленникам.

Поставь прокси перед

Вы также можете запустить PgBouncer или PgPool-II перед PostgreSQL, выступая в качестве пула соединений и прокси. Таким образом, вы можете позволить прокси обрабатывать SSL, а не реальный хост базы данных. Прокси может находиться на отдельной ВМ или машине.

В любом случае, использование PostgreSQL с прокси-серверами соединений является хорошей идеей, если только у клиентского приложения нет встроенного пула. Большинство серверов приложений Java, Rails и т. Д. Имеют встроенный пул. Даже в этом случае прокси-серверы на стороне сервера в худшем случае безвредны.

Простое продолжение внушительного плана действий Крейгса:

Возможно, пользователь использует только относительно небольшой набор сетевых провайдеров (например, его провайдер мобильной сети во время переезда, его кабельная сеть из дома и с рабочего места, исходящая IP-связь с работы).

Большинство сетевых провайдеров имеют много IP-адресов, но не очень много подсетей. Таким образом, вы можете задать фильтр iptables, который ограничивает доступ postgresql к сегментам сети, которые используются вашим клиентом. Это значительно уменьшило возможности атаки случайно выбранных источников проблем в сети.

Простой сценарий поддержки:

  1. Ваш клиент звонит вам: "Я не могу войти".
  2. Вы узнаете с tcpdump -i eth0 -p tcp port 5432 команда, откуда он приходит.
  3. С whois 1.2.3.4 Вы можете получить IP-адрес, используемый этим IP-адресом. Например, это может быть 1.2.3.0/24,
  4. С iptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT (или что-то подобное) вы разрешаете tcp-соединения с его новой подсетью.

Существует очень хороший Perl-скрипт с именем uif который может обеспечить постоянные и интуитивно понятные наборы правил iptables. (Google для "UIF Iptables").

Вот довольно простая конфигурация Fail2ban для PostgreSQL, основанная на HOWTO, связанном выше, но настроенная для реальной работы с пакетами Ubuntu, перехвата другого состояния ошибки и пропуска различных отладочных сообщений, чтобы ускорить его:

/etc/fail2ban/filter.d/local-postgresql.conf:

[Definition]

failregex = <HOST>\(\d+\) FATAL:  password authentication failed for .+$
            <HOST>\(\d+\) FATAL:  no pg_hba.conf entry for host .+$

ignoreregex = duration:

/etc/fail2ban/jail.d/local-postgresql.conf:

[local-postgresql]
enabled  = true
filter   = local-postgresql
action   = iptables[name=PostgreSQL, port=5432, protocol=tcp]
           sendmail-whois[name=PostgreSQL, dest=root@localhost]
logpath  = /var/log/postgresql/postgresql-9.3-main.log
maxretry = 3

Fail2ban - мощный инструмент, но не верьте, что фильтр будет работать как есть. Протестируйте все фильтры, используя инструмент failregex, и не забывайте избегать любых кавычек (т. Е. "Admin" будет "admin"). В качестве примера, тестирование следующей строки failregex фильтра из моего /etc/log/postgresql/postgresql-9.3-main.log не сработало для меня.

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' '<HOST>\(\d+\) FATAL:  password authentication failed for .+$'

Вышеуказанное дало мне

Failregex: 0 всего

Мне пришлось обновить failregex, чтобы он соответствовал формату журнала.

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' 'FATAL:  password authentication failed for user \"<HOST>\"'

Это дало мне положительный результат.

Failregex: 1 всего

Тест fail2ban-regex также может быть реализован для целых файлов журнала.

fail2ban-regex /var/log/postgresql/postgresql-9.3-main.log /etc/fail2ban/filter.d/postgresql.local

Вышесказанное дало мне следующий положительный результат с обновленным failregex.

Failregex: всего 169

У меня возникла проблема с настройкой Fail2ban из-за отсутствия IP-адреса в конфигурации журнала PostgreSQL по умолчанию. Я использую PostgreSQL 12 и 13 в Debian 10. Так что, если кто-нибудь столкнется с тем же, вот как это исправить.

/etc/postgresql/13/main/postgresql.conf

      log_line_prefix = '%m {%h} [%p] %q%u@%d '

По умолчанию было:'%m [%p] %q%u@%d '. я добавил%hпередать IP-адрес в Fail2ban.

/etc/fail2ban/filter.d/postgresql.conf

      [Definition]
failregex = \{<HOST>\} .+? FATAL:  password authentication failed for user .+$

/etc/fail2ban/jail.d/postgresql.conf

      [postgresql]

enabled = true
filter = postgresql
logpath = /var/log/postgresql/postgresql*.log
maxretry = 3
bantime = 86400
port = 5432

Затем перезапустите службу Fail2ban.systemctl restart fail2ban.

И смотреть логиtail -f /var/log/fail2ban.log.

Другие вопросы по тегам