Назад | Перейти на главную страницу

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

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

По понятным причинам мы не можем сказать просто «нет», только в крайнем случае.

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

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

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

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

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

Требовать SSL

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

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

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

hostssl theuser thedatabase 1.2.3.4/32 md5

... возможно, со словом «все» для пользователя и / или базы данных и, возможно, с более широким фильтром 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, которому доверяет сервер. Необязательно использовать тот же ЦС, что и сертификат сервера, вы можете сделать это с помощью доморощенного ЦС openssl. Пользователь JDBC должен импортировать сертификат клиента в свое хранилище ключей Java с помощью keytool и, возможно, настроить некоторые системные свойства JSSE так, чтобы они указывали Java на их хранилище ключей, чтобы оно не было полностью прозрачным.

Поместить экземпляр в карантин

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

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

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

Мне не следовало говорить это, но ...

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

Использовать нестандартный порт

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

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

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

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

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

Вот довольно простая конфигурация 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

Простое расширение впечатляющего плана действий Крейгса:

Возможно, пользователь использует лишь относительно небольшой набор сетевых провайдеров (например, его мобильный сетевой провайдер во время движения, его кабельная сеть из дома и исходящий 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 - мощный инструмент, но не верьте, что фильтр будет работать как есть. Проверьте любые фильтры с помощью инструмент failregex, и не забудьте избегать кавычек (т.е. "admin" будет \ "admin \"). Например, тестирование следующей строки filter 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