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

29

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

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

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

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

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

Иосип Роден
источник
4
SSH туннели не вариант? Эта практическая статья на самом деле использует PostgreSQL в качестве примера. Вы можете предоставить клиенту предварительно настроенный SSH-клиент для упрощения подключения.
Люцифер Сэм
@LuciferSam Нет. БД будет использоваться собственным Java-приложением на 100 машинах компании. Наш единственный способ настроить их - предоставить URL-адрес соединения jdbc для их администрирования локальной сети, любой другой очень-очень проблематичен.
@milkman что делает приложение? возможно, он может запросить сервер RESTful вместо этого? Очевидно, что передача SQL в REST ничего не дает, но при условии, что это CRUD ..
tedder42
@ tedder42 Управляет базой данных пользователей CMS, которая также размещается у нас. У нас нет разрешения на изменение источника.

Ответы:

41

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

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

Требовать SSL

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

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

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

hostssl theuser thedatabase 1.2.3.4/32 md5

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

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

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

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

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

REVOKECONNECTправо из 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 должен импортировать сертификат клиента keytoolв свое хранилище ключей Java и, возможно, настроить некоторые системные свойства JSSE, чтобы указывать Java на свое хранилище ключей, поэтому он не является полностью прозрачным.

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

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

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

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

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

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

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

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

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

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

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

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

Крейг Рингер
источник
3
Если у клиента есть статический $ IP, разрешите это только через брандмауэр на порт $.
user9517 поддерживает GoFundMonica
Большое спасибо! Pgjdbc имеет этот параметр, но я могу дать ему только URL-адрес соединения jdbc, и я не уверен, будет ли он работать с его Java-приложением (проприетарным, отладочным). Хорошо, если нет, я задам новый вопрос. Спасибо за ваш подробный ответ!
1
@lesto На самом деле, я думаю, что использование VPN значительно увеличивает поверхность атаки по сравнению с одним ограниченным сервисом. Люди забывают, что VPN становится каналом атаки для любого вредоносного ПО на удаленной машине (машинах), чтобы пробить всю периметр безопасности и добраться до кишок сети. Я нахожу их приемлемыми только в том случае, если они подключаются к демилитаризованной зоне, которая относится к ним так же токсично, как и к интернет-хостам.
Крейг Рингер,
1
@CraigRinger Я не говорю, чтобы удалить остальную часть защиты, но чтобы инкапсулировать сервис в VPN
Lesto
1
@lesto Конечно, согласен, VPN может быть полезным дополнительным слоем, если он не рассматривается как Magic Security Sauce, как, к сожалению, делают многие администраторы.
Крейг Рингер,
2

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

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

Петер говорит восстановить Монику
источник
1
Интересная идея, но звучит немного хрупко.
nishantjr
@nishantjr Конечно, это не отдельное решение, а только возможность улучшить ситуацию.
Петер говорит восстановить Монику
Более практичным подходом может быть внесение в белый список отдельных интернет-провайдеров и / или стран, способы этого см., Например, stackoverflow.com/questions/16617607/…
Йосип Роден,
1

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

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

metersales
источник