Jak zabezpieczyć bazę PostgreSQL przed dostępem z zewnątrz?
Podziel się

W poniższym artykule skupię się na metodach zabezpieczenia bazy PostgreSQL przed nieuprawnionym dostępem z zewnątrz (na przykładzie bazy PostgreSQL w wersji 11).

W bazie danych mogą być przechowywane różne informacje, np. o kontach użytkowników aplikacji internetowej, dane finansowe, osobowe, itp. Dostęp do takich danych nich powinien być limitowany jedynie do uprawnionych osób.

Nieuprawniony dostęp do tych może skutkować ich przejęciem, modyfikacją lub skasowaniem. Firma narażona jest wtedy na straty finansowe, a w przypadku usunięcia lub modyfikacji danych może dojść do przerwania ciągłości działania. Pozyskane dane klientów mogą być wykorzystane w celach do szantażu, wywołania strat finansowych lub wizerunkowych. Od bezpieczeństwa danych zależą więc często dalsze losy firmy i zaufanie klientów.

Często baza danych jest jednym z elementów back-endu platformy elektronicznej i znajduje się na serwerze umieszczonym w sieci. W takiej sytuacji, klienci zazwyczaj nie mają bezpośredniego dostępu do bazy, gdyż między nimi znajduje się aplikacja i to ona przekształca żądania klientów na zapytania do bazy.

Źle zaprojektowana aplikacja może być wykorzystana do ataków. Jako przykład posłużyć może atak typu sql injection, podczas którego dochodzi do takiej modyfikacji zapytania, aby robiło coś więcej, niż faktycznie powinno.

W wielu firmach praktykuje się również bezpośredni dostęp pracowników do bazy. Najczęściej są to analitycy przekształcający dane na wiele sposobów, w celu uzyskania dodatkowych wskaźników czy trendów. Nieuczciwy pracownik lub nieuprawniona osoba, która pozyskała dane logowania pracownika, może pobrać dane z bazy, a następnie wystawić na sprzedaż.

W artykule pominę zabezpieczenia systemowe (vpn, stunnel, firewall, sudoers, etc.). Skupię się natomiast na możliwościach w zakresie bezpieczeństwa, dostępnych w samej bazie PostgreSQL, a konkretnie związanych z dostępem z zewnątrz hosta, na której pracuje baza.

Próba dostępu do bazy z zewnętrznego IP

Atakujący próbuje wykorzystać możliwość podłączenia się z zewnętrznego IP na standardowy port, na którym pracuje baza, czyli 5432.

Zmiana portu, na którym nasłuchuje serwer

Pierwszym zabezpieczeniem będzie zmiana standardowego portu, na którym pracuje baza.

Jednak musimy wiedzieć, gdzie jest plik konfiguracyjny dla naszej bazy PostgreSQL. W tym celu logujemy się do shell na usera, na którym działa baza – domyślnie jest to user postgres. Uruchamiamy polecenie psql i wydajemy polecenia:

postgres@localhost:~$ psql
psql (13.2 (Ubuntu 13.2-1.pgdg20.04+1), server 11.11 (Ubuntu 11.11-1.pgdg20.04+1))
Type "help" for help.


postgres=# show config_file ;
               config_file               
-----------------------------------------
 /etc/postgresql/11/main/postgresql.conf
(1 row)

postgres=# show port ;
port 
------
 5432
(1 row)

Widać, że baza działa na porcie 5432, a plik konfiguracyjny jest w lokalizacji  /etc/postgresql/11/main/postgresql.conf

Tutaj uwaga. Powyższa lokalizacja pliku konfiguracyjnego to przykład dla dystrybucji Debian, ale w większości systemów plik ten umieszczany jest wewnątrz katalogu z plikami bazy.

W celu zmiany portu, na którym nasłuchuje nasza baza, modyfikujemy parametr o nazwie port w pliku postgresql.conf.

port = 5432                             # (change requires restart)

Zmieniamy na dowolny, jaki nam odpowiada – dla przykładu modyfikujemy na 55432:

port = 55432                            # (change requires restart)

Warto również zauważyć, że zmiana tego parametru wymaga wykonania restartu bazy. Po restarcie baza działa już na zmienionym porcie – wymagane jest podawanie portu w parametrze -p lub umieszczenie w zmiennej systemowej o nazwie PGPORT.

postgres@localhost:~$ psql
psql: error: could not connect to server: Nie ma takiego pliku ani katalogu
	Is the server running locally and accepting
	connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

postgres@localhost:~$ psql -p 55432
psql (13.2 (Ubuntu 13.2-1.pgdg20.04+1), server 11.11 (Ubuntu 11.11-1.pgdg20.04+1))
Type "help" for help.

postgres=#

Ograniczenie nasłuchiwania na wybranych interfejsach sieciowych

Oprócz zmiany portu nasłuchującego możemy również wskazać konkretne interfejsy sieciowe (ich adresy IP lub nazwy DNS), na których baza będzie nasłuchiwać. Zmiany dokonujemy poprzez ich wskazanie w parametrze listen_addresses.

Domyślnie baza ma wpisany tylko interfejs wewnętrzny – ‘localhost’, ale później często bywa ustawiany na wszystkie interfejsy – ‘*’

Ograniczenie dostępu tylko dla określonej listy adresów IP

Kolejnym zabezpieczeniem będzie ograniczenie dostępu do bazy tylko dla określonych użytkowników i określonych dla nich adresów IP – Host Base Access. Konfiguracja jest zawarta w pliku pg_hba.conf.

Położenie pliku jest określone przez parametr w bazie hba_file – najczęściej znajduje się on w katalogu bazy. Odczytane przez bazę reguły z tego pliku znajdują się w widoku pg_hba_file_rules. Każda linia w pliku stanowi oddzielną regułę. Reguły umieszczone wyżej są bardziej istotne – użyta jest pierwsza reguła, która spełni warunki. Pola w linii oddzielone są spacjami lub tabulatorami.

Pierwsze pole określa typ połączenia:

  • wykorzystanilocal – z użyciem unix-domain sockets – logowanie lokalne (np. /var/run/postgresql/.s.PGSQL.5432)
  • host – z użyciem TCP/IP poprzez interfejsy sieciowe (parametr listen_addresses domyślnie localhost, ale najczęściej ‘*’)
  • Hostssl – z użyciem TCP/IP z szyfrowaniem transmisji SSL
  • Hostnossl – z użyciem TCP/IP, ale tylko bez szyfrowania
  • Hostgssenc – z użyciem TCP/IP z użyciem szyfrowania GSSAPI (serwer musi mieć wbudowane wsparcie GSSAPI)

Drugie pole określa nazwę bazy, do której klient się łączy:

  • all – określa zgodność nazwy do dowolnej bazy
  • sameuser – określa zgodność nazwy do bazy zgodnej z loginem użytkownika
  • samerole, samegroup – określa zgodność nazwy do bazy zgodnej z nazwą roli, jaką musi posiadać użytkownik
  • replication – określa połączenie dla fizycznej replikacji

Można określić kilka nazw baz danych, rozdzielając je przecinkiem. Nazwy baz mogą być też zawarte w osobnym pliku, a zamiast nazwy podany plik w formacie: @nazwa_pliku.

Trzecie pole określa użytkownika:

  • all – określa zgodność nazwy do dowolnego użytkownika
  • Replication – określa połączenie dla fizycznej replikacji
  • +rola – określa zgodność z userem, który posiada rolę

Również w tym wypadku użytkownicy mogą być w osobnym pliku.

Kolejne pole określa adres, z którego łączy się klient:

  • Nazwa DNS hosta
  • Wszystkie hosty z domeny – dns zaczynający się od kropki
  • Zakres adresów IP – Adres/długość maski IPv4/IPv6
  • Zakres adresów IP – Adres spacja i maska IPv4/IPv6
  • samehost – wszystkie adresy interfejsów serwera
  • samenet – wszystkie adresy z tej samej podsieci co serwer

Korzystanie z nazw DNS nie jest zalecane ze względu na narzut czasowy na rozwiązywanie IP na nazwę DNS.

Następne pole określa wykorzystaną metodę identyfikacji:

  • trust – bez weryfikacji
  • reject – odrzucenie połączenia
  • scram-sha-256 – bezpieczna metoda logowania z użyciem bezpiecznego mechanizmu challenge-response SCRAM-SHA-256
  • md5 – logowanie z użyciem mechanizmu challenge-response md5 lub scram-sha-256
  • password – logowanie z użyciem nieszyfrowanego hasła
  • gss – logowanie z użyciem GSSAPI
  • sspi – tylko dla Windows
  • ident – logowanie z użyciem serwera Ident
  • peer – tylko dla lokalnych połączeń – login zalogowanego użytkownika na shell
  • ldap – autentykacja z użyciem serwera LDAP
  • radius – autentykacja z użyciem serwera Radius
  • cert – autentykacja z użyciem certyfikatów SSL
  • pam – autentykacja z użyciem PAM (Pluggable Authentication Modules)
  • bsd – autentykacja z użyciem serwisu BSD Authentication

Ostatnie opcjonalne pole określa opcję dla autentykacji:

  • nazwa=wartość

Przykładowy plik może wyglądać tak:

# TYPE       DATABASE        USER            ADDRESS              METHOD
# user 
host          bazaa          usera         10.1.2.1/32             md5
host          bazaa          userb         10.1.2.2/32             md5

# szyfrowanie + logowanie certyfikatem
hostssl       bazab          usera         10.1.2.1/32             cert

# lokalne połączenia 
host          etl            etl           127.0.0.1/32            md5
host          student        student       127.0.0.1/32            md5

Aby było możliwe połączenie się z użyciem ssl należy w konfiguracji bazy ustawić parametry związane z ssl:

  • ssl ustawić na on
  • ssl_cert_file – ścieżka do pliku pem z certyfikatem dla bazy
  • ssl_key_file – ścieżka do pliku key z kluczem prywatnym
  • ssl_passphrase_command – komenda shell powodująca zwrotkę w postaci hasła do klucza prywatnego, np. echo

Samo umieszczenie reguł w pliku nie spowoduje automatycznego ich odświeżenia. W tym celu należy na bazie wymusić przeładowanie konfiguracji, co można zrobić poprzez:

  • zapytanie select pg_reload_conf()
  • komendę pg_ctl reload
  • komendę sudo systemctl reload postgresql@11-main.service (jeśli startem bazy zarządza demon systemd)

Mam nadzieję, że artykuł był dla Ciebie pomocny.

W kolejnych częściach postaram się poruszyć inne metody zabezpieczenia bazy PostgreSQL przed nieuprawnionym dostępem

Zapraszam do śledzenia naszego bloga.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

    Skontaktuj się z nami