So sichern Sie einen offenen PostgreSQL-Port

29

Das ist also die Situation. Es scheint, dass wir einen offenen TCP-Port 5432 für die Welt benötigen, über den ein Kunde Zugriff auf seine PostgreSQL-Datenbank hat.

Aus offensichtlichen Gründen können wir nicht einfach "nein" sagen, sondern nur als letztes Mittel.

Was sind die größten Probleme? Wie kann ich unsere Infrastruktur verteidigen?

Wie auch immer: Warum sollte es nicht für die Welt geöffnet werden? Ich denke, vielleicht ist es sicherer als ein 20 Jahre alter, nicht gewarteter FTP-Server.

PS VPN ist nicht in Ordnung. Etwas Verschlüsselung vielleicht (wenn ich ihm eine JDBC-Verbindungs-URL geben kann, die funktioniert ).

Josip Rodin
quelle
4
SSH-Tunnel sind keine Option? In diesem Artikel wird PostgreSQL als Beispiel verwendet. Sie können dem Kunden einen vorkonfigurierten SSH-Client zur Verfügung stellen, um die Verbindung zu vereinfachen.
Lucifer Sam
@LuciferSam Nein. Die Datenbank wird von einer selbst entwickelten Java-Anwendung auf rund 100 Firmenmaschinen verwendet. Unsere einzige Möglichkeit, sie zu konfigurieren, besteht darin, ihrer Localnet-Administration eine JDBC-Verbindungs-URL zuzuweisen. Alle anderen sind sehr, sehr problematisch.
@milkman was macht die App? Vielleicht könnte es stattdessen einen RESTful-Server abfragen? Es ist offensichtlich, dass die Übergabe von SQL an REST nichts bringt, vorausgesetzt, es handelt sich um CRUD ..
tedder42
@ tedder42 Manipuliert die Datenbank des CMS des Benutzers, die auch von uns gehostet wird. Wir haben keine Erlaubnis, die Quelle zu ändern.

Antworten:

41

Benötigen Sie SSL, lassen Sie SELinux aktiviert, überwachen Sie die Protokolle und verwenden Sie eine aktuelle PostgreSQL-Version .

Serverseite

SSL erforderlich

In postgresql.confReihe ssl=onund stellen Sie sicher , dass Ihre Schlüsseldatei und certfile angemessen (die Dokumentation und die Kommentare in sehen installiert postgresql.conf).

Möglicherweise müssen Sie ein Zertifikat von einer Zertifizierungsstelle kaufen, wenn Sie möchten, dass es von Clients ohne spezielle Einrichtung auf dem Client als vertrauenswürdig eingestuft wird.

In pg_hba.confGebrauch so etwas wie:

hostssl theuser thedatabase 1.2.3.4/32 md5

... möglicherweise mit "all" für Benutzer und / oder Datenbank und möglicherweise mit einem breiteren Quell-IP-Adressfilter.

Beschränken Sie die Anzahl der Benutzer, die sich anmelden können, und verweigern Sie die Anmeldung als Remote-Superuser

Erlaube nicht "alle" für Benutzer, wenn möglich; Sie möchten Superuser-Anmeldungen nicht remote zulassen, wenn dies nicht erforderlich ist.

Beschränken Sie die Rechte der Benutzer

Schränken Sie die Rechte des Benutzers (n) , die sich anmelden können. Sie sie nicht geben CREATEDBoder CREATEUSERRechte.

REVOKEKlicken Sie auf das CONNECTRecht von PUBLICin allen Ihren Datenbanken und geben Sie es dann nur den Benutzern / Rollen zurück, die auf diese Datenbank zugreifen dürfen. (Gruppieren Sie Benutzer in Rollen und erteilen Sie Berechtigungen für Rollen, nicht direkt für einzelne Benutzer).

Stellen Sie sicher, dass Benutzer mit Remotezugriff nur eine Verbindung zu den von ihnen benötigten DBs herstellen können und nur Rechte für die Schemas, Tabellen und Spalten haben, die sie tatsächlich benötigen. Dies ist auch für lokale Benutzer eine gute Praxis, es ist nur eine vernünftige Sicherheit.

Client-Setup

Übergeben Sie in PgJDBC den Parameterssl=true :

Um den JDBC-Treiber anzuweisen, eine SSL-Verbindung herzustellen, müssen Sie den Verbindungs-URL-Parameter ssl = true hinzufügen.

... und installieren Sie das Serverzertifikat im Truststore des Clients oder verwenden Sie ein Serverzertifikat, das von einer der CAs im integrierten Truststore von Java als vertrauenswürdig eingestuft wird, wenn der Benutzer das Zertifikat nicht installieren muss.

Laufende Maßnahmen

Stellen Sie nun sicher, dass Sie PostgreSQL auf dem neuesten Stand halten . PostgreSQL hatte nur ein paar Sicherheitslücken vor der Authentifizierung, aber das ist mehr als null. Bleiben Sie also auf dem Laufenden. Sie sollten trotzdem Bugfixes haben.

Fügen Sie eine Firewall voran, wenn es große Netblocks / Regionen gibt, von denen Sie wissen, dass Sie nie Zugriff benötigen.

Verbindungen und Verbindungen protokollieren (siehe postgresql.conf). Fragen protokollieren, falls sinnvoll. Führen Sie ein Intrusion Detection-System oder ein Fail2Ban-System oder ähnliches aus, falls dies sinnvoll ist. Für fail2ban mit Postgres, gibt es eine bequeme How-to hier

Überwachen Sie die Protokolldateien.

Bonus Paranoia

Zusätzliche Schritte zum Nachdenken ...

Client-Zertifikate anfordern

Wenn Sie möchten, können Sie auch festlegen pg_hba.conf, dass der Client ein vom Server als vertrauenswürdig eingestuftes X.509-Clientzertifikat vorlegt. Es muss nicht dieselbe Zertifizierungsstelle wie das Serverzertifikat verwendet werden. Sie können dies mit einer homebrew openssl-Zertifizierungsstelle tun. Ein JDBC-Benutzer muss das Client-Zertifikat mit in seinen Java-Keystore importieren keytoolund möglicherweise einige JSSE-Systemeigenschaften so konfigurieren, dass Java auf seinen Keystore verweist, sodass es nicht vollständig transparent ist.

Instanz unter Quarantäne stellen

Wenn Sie wirklich paranoid sein möchten, führen Sie die Instanz für den Client in einem separaten Container / einer separaten VM oder zumindest unter einem anderen Benutzerkonto mit nur den erforderlichen Datenbanken aus.

Auf diese Weise kommen sie nicht weiter, wenn sie die PostgreSQL-Instanz kompromittieren.

Verwenden Sie SELinux

Ich sollte das nicht sagen müssen, aber ...

Führen Sie einen Computer mit SELinux-Unterstützung wie RHEL 6 oder 7 aus und schalten Sie SELinux nicht aus und setzen Sie ihn nicht in den zulässigen Modus . Behalten Sie den Erzwingungsmodus bei.

Verwenden Sie einen nicht standardmäßigen Port

Sicherheit nur durch Dunkelheit ist Dummheit. Sicherheit, die ein wenig Dunkelheit verbraucht, wenn Sie die vernünftigen Dinge getan haben, wird wahrscheinlich nicht schaden.

Führen Sie Pg auf einem nicht standardmäßigen Port aus, um automatisierten Angreifern das Leben etwas zu erschweren.

Stell einen Proxy voran

Sie können auch PgBouncer oder PgPool-II vor PostgreSQL ausführen, das als Verbindungspool und Proxy fungiert. Auf diese Weise können Sie festlegen, dass der Proxy SSL verarbeitet, nicht den tatsächlichen Datenbankhost. Der Proxy kann sich auf einer separaten VM oder Maschine befinden.

Die Verwendung von Verbindungspooling-Proxys ist bei PostgreSQL im Allgemeinen sowieso eine gute Idee, es sei denn, die Client-App verfügt bereits über einen integrierten Pool. Die meisten Java-Anwendungsserver, Rails usw. verfügen über ein integriertes Pooling. Selbst dann ist ein Server-Side-Pooling-Proxy im schlimmsten Fall harmlos.

Craig Ringer
quelle
3
Wenn der Client eine statische $ IP hat, lasse dies nur über die Firewall zu $ ​​port.
user9517 unterstützt GoFundMonica
Vielen Dank! Pgjdbc hat diesen Parameter, aber ich kann ihm nur eine jdbc-Verbindungs-URL geben, und ich bin nicht sicher, ob es mit seiner Java-Anwendung (proprietär, undebuggbar) funktionieren wird. Ok, wenn nicht, werde ich eine neue Frage stellen. Vielen Dank für Ihre ausführliche Antwort!
1
@lesto Eigentlich glaube ich, dass das Freilegen eines VPN die Angriffsfläche im Vergleich zu nur einem eingeschränkten Dienst massiv erhöht. Die Leute vergessen, dass das VPN dann zu einem Angriffskanal für Malware auf den Remotecomputern wird, um die gesamte Perimetersicherheit zu durchdringen und die Eingeweide des Netzwerks zu erreichen. Ich finde sie nur akzeptabel, wenn sie eine Verbindung zu einer DMZ herstellen, die sie als genauso giftig wie Internet-Hosts behandelt.
Craig Ringer
1
@CraigRinger Ich sage nicht, um den Rest des Schutzes zu entfernen, sondern um den Dienst in VPN zu kapseln
Lesto
1
Sicher, ein VPN kann eine nützliche zusätzliche Ebene sein, wenn es nicht wie eine Magic Security Sauce behandelt wird, wie es leider viele Administratoren tun.
Craig Ringer
2

Eine einfache Erweiterung zu Craigs beeindruckendem Aktionsplan:

Möglicherweise verwendet der Benutzer nur eine relativ kleine Gruppe von Netzwerkanbietern (z. B. seinen Mobilfunkanbieter beim Umzug, sein Kabelnetzwerk von zu Hause aus und seine IP-Adresse am Arbeitsplatz ausgehend von der Arbeit).

Die meisten Netzwerkanbieter haben viele IPs, aber nicht wirklich viele Subnetze. Sie können also einen iptables-Filter festlegen, der den Post-Gresql-Zugriff auf die Netzwerksegmente beschränkt, die von Ihrem Kunden verwendet werden. Dies reduzierte die Angriffsmöglichkeiten von zufällig ausgewählten Störquellen des Netzes erheblich.

Ein einfaches Support-Szenario:

  1. Ihr Kunde ruft Sie an, "Ich kann mich nicht anmelden" .
  2. Mit einem tcpdump -i eth0 -p tcp port 5432Befehl erfahren Sie , woher er kommt.
  3. Mit a whois 1.2.3.4können Sie die von dieser IP verwendete IP-Adresse ermitteln. Zum Beispiel kann es sein 1.2.3.0/24.
  4. Mit einem iptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT(oder einem ähnlichen) erlaubt man die TCP-Verbindungen mit seinem neuen Subnetz.

Es gibt ein sehr gutes Perl-Skript, uifdas permanente und intuitive deklarierbare iptables-Regelsätze bereitstellen kann. (Google für "uif iptables").

sagt Peter, stell Monica wieder her
quelle
1
Interessante Idee, aber das klingt ein bisschen fragil.
Nishantjr
@nishantjr Natürlich ist es keine eigenständige Lösung, sondern nur eine Möglichkeit, die Dinge zu verbessern.
Peter sagt wieder Monica
Ein praktischerer Ansatz könnte darin bestehen, einzelne ISPs und / oder Länder auf die Positivliste
Josip Rodin,
1

Hier ist eine ziemlich einfache Fail2ban-Konfiguration für PostgreSQL, die auf dem oben verlinkten HOWTO basiert, aber genau auf die Arbeit mit Ubuntu-Paketen abgestimmt ist.

/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
Josip Rodin
quelle
1

Fail2ban ist ein leistungsstarkes Tool, aber vertrauen Sie nicht darauf, dass ein Filter so funktioniert, wie er ist. Testen Sie alle Filter mit dem Failregex-Tool und denken Sie daran, Anführungszeichen zu entfernen (dh "admin" wäre "admin"). Das Testen der folgenden filter failregex-Zeile in meiner Datei /etc/log/postgresql/postgresql-9.3-main.log hat beispielsweise bei mir nicht funktioniert.

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

Das Obige hat mir gegeben

Failregex: 0 insgesamt

Ich musste das Failregex aktualisieren, um es an das Protokollformat anzupassen.

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

Dies gab mir ein positives Ergebnis.

Failregex: 1 gesamt

Der fail2ban-regex-Test kann auch für ganze Protokolldateien implementiert werden.

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

Das obige hat mir das folgende positive Ergebnis mit dem aktualisierten Failregex gebracht.

Failregex: 169 insgesamt

meterales
quelle