Frage wie man einen offenen PostgreSQL-Port sichert


Also, das ist die Situation. Es scheint, dass wir einen offenen TCP-Port 5432 für die Welt haben müssen, wo ein Kunde Zugang zu seiner PostgreSQL-Datenbank hat.

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

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

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

P.S. VPN ist nicht in Ordnung. Einige Verschlüsselung könnte sein (wenn ich ihm eine JDBC-Verbindungs-URL geben kann, die funktioniert).


29
2017-09-09 06:41


Ursprung


SSH-Tunnel sind keine Option? Dieser How-To-Artikel verwendet tatsächlich PostgreSQL als Beispiel. Sie können dem Kunden einen vorkonfigurierten SSH-Client zur Verfügung stellen, um die Verbindung zu erleichtern. - Lucifer Sam
@LuciferSam Nein. Die db wird von einer eigens entwickelten Java-Anwendung auf rund 100 Firmenmaschinen verwendet. Unsere einzige Möglichkeit, sie zu konfigurieren, besteht darin, eine jdbc-Verbindungs-URL zu ihrer lokalen Netzwerkverwaltung zu geben, jede andere ist sehr, sehr problematisch.
@milkman was macht die App? vielleicht könnte es stattdessen einen RESTful-Server abfragen? Es ist offensichtlich, dass das Übergeben von SQL an REST nichts bringt, aber angenommen, es ist CRUD. - tedder42
@ Tedder42 Es manipuliert die Datenbank des Benutzer-CMS, die auch von uns gehostet wird. Wir sind nicht berechtigt, die Quelle zu ändern.


Antworten:


Erfordern Sie SSL, halten Sie SELinux eingeschaltet, überwachen Sie die Protokolle und Verwenden Sie eine aktuelle PostgreSQL-Version.

Serverseite

Erfordern SSL

Im postgresql.conf einstellen ssl=on und stellen Sie sicher, dass Sie Ihr Keyfile und Ihre certfile korrekt installiert haben (siehe die Dokumentation und die Kommentare in postgresql.conf).

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

Im pg_hba.conf benutze 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 Quellen-IP-Adressenfilter.

Begrenzen Sie Benutzer, die sich anmelden können, verweigern Sie dem Remote-Superuser-Login

"All" für Benutzer nicht zulassen, wenn möglich; Sie möchten Superuser-Anmeldungen nicht remote zulassen, wenn Sie die Notwendigkeit vermeiden können.

Beschränken Sie die Rechte der Benutzer

Beschränken Sie die Rechte der Benutzer, die sich anmelden können. Geben Sie sie nicht an CREATEDB oder CREATEUSER Rechte.

REVOKE das CONNECT direkt aus PUBLIC in allen Ihren Datenbanken, dann geben Sie es nur an die Benutzer / Rollen zurück, die auf diese Datenbank zugreifen können sollen. (Gruppieren Sie Benutzer zu Rollen und gewähren Sie Rollen Rechte und nicht direkt einzelnen Benutzern).

Stellen Sie sicher, dass Benutzer mit Remotezugriff nur eine Verbindung mit den benötigten DBs herstellen können und nur über Berechtigungen für die Schemas, Tabellen und Spalten verfügen, die sie tatsächlich benötigen. Dies ist auch für lokale Benutzer eine gute Methode, es ist nur eine vernünftige Sicherheit.

Client-Einrichtung

Übergeben Sie in PgJDBC den Parameter ssl=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 soll.

Laufende Maßnahmen

Jetzt stellen Sie sicher, dass Sie PostgreSQL auf dem neuesten Stand halten. PostgreSQL hat nur ein paar Sicherheitslücken vor der Authentifizierung, aber das ist mehr als null, also bleib auf dem Laufenden. Sie sollten sowieso, Bugfixes sind schöne Dinge zu haben.

Fügen Sie eine Firewall im Vordergrund hinzu, wenn große Netzblöcke / Regionen vorhanden sind, von denen Sie wissen, dass Sie nie Zugriff benötigen.

Protokollverbindungen und Verbindungsabbrüche (siehe postgresql.conf). Protokollieren Sie Abfragen, wenn dies praktisch ist. Führen Sie ein Intrusion Detection System oder fail2ban o.ä. vor, falls dies praktikabel ist. Für fail2ban mit Postgres gibt es ein praktisches How-To Hier

Überwachen Sie die Protokolldateien.

Bonusparanoia

Zusätzliche Schritte zum Nachdenken ...

Erfordern Clientzertifikate

Wenn Sie möchten, können Sie auch verwenden pg_hba.conf Erfordern, dass der Client ein X.509-Clientzertifikat präsentiert, das vom Server als vertrauenswürdig eingestuft wird. Es muss nicht die gleiche CA wie das Server-Zertifikat verwenden, Sie können dies mit einer homebrew openssl CA tun. Ein JDBC-Benutzer muss das Client-Zertifikat in seinen Java-Keystore mit importieren keytool und möglicherweise einige JSSE-Systemeigenschaften so konfigurieren, dass Java auf ihren Keystore verweist, sodass es nicht vollständig transparent ist.

Isolieren Sie die Instanz in Quarantäne

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

Wenn sie die PostgreSQL-Instanz kompromittieren, kommen sie nicht weiter.

Verwenden Sie SELinux

Ich müsste das nicht sagen, aber ...

Führen Sie einen Rechner mit SELinux-Unterstützung wie RHEL 6 oder 7 und Schalten Sie SELinux nicht aus oder stellen Sie es auf den zulässigen Modus ein. Behalte es im Erzwingungsmodus.

Verwenden Sie einen nicht standardmäßigen Port

Sicherheit durch nur Dunkelheit ist Dummheit. Sicherheit, die ein wenig Unklarheit benutzt, sobald Sie die vernünftigen Sachen getan haben, wird wahrscheinlich nicht schaden.

Führen Sie Pg auf einem nicht standardmäßigen Port aus, um das Leben für automatisierte Angreifer etwas zu erschweren.

Setzen Sie einen Proxy vor

Sie können PgBouncer oder PgPool-II auch vor PostgreSQL ausführen und als Verbindungspool und Proxy fungieren. Auf diese Weise können Sie zulassen, dass der Proxy SSL verarbeitet und nicht der eigentliche Datenbankhost. Der Proxy kann sich auf einer separaten VM oder Maschine befinden.

Die Verwendung von Verbindungs-Pooling-Proxies ist im Allgemeinen eine gute Idee mit PostgreSQL, es sei denn, die Client-App hat bereits einen integrierten Pool. Die meisten Java-Anwendungsserver, Rails usw. verfügen über ein integriertes Pooling. Selbst dann ist ein serverseitiger Pooling-Proxy im schlimmsten Fall harmlos.


41
2017-09-09 07:03



Wenn der Client eine statische $ IP hat, erlaube das nur über die Firewall zu $ ​​port. - Iain
Vielen Dank! Pgjdbc hat diesen Parameter, aber ich kann ihm nur eine jdbc-Verbindungs-URL geben, und ich bin mir nicht sicher, ob es mit seiner Java-Anwendung funktionieren wird (proprietär, nicht entpackbar). Ok, wenn nicht, werde ich eine neue Frage stellen. Danke deine ausführliche Antwort!
@lesto Eigentlich denke ich, ein VPN auszusetzen massiv erhöht die Angriffsfläche im Vergleich zu nur einem eingeschränkten Dienst. Die Leute vergessen, dass das VPN dann zu einem Angriffskanal für jede Malware auf dem / den entfernten Rechner (n) wird, die die gesamte Perimeter-Sicherheit durchbricht und in den Kern des Netzwerks gelangt. Ich finde sie nur akzeptabel, wenn sie sich mit einer DMZ verbinden, die sie genauso giftig behandelt wie Internet-Hosts. - Craig Ringer
@CraigRinger Ich sage nicht, um den Rest des Schutzes zu entfernen, sondern um Service in VPN einzukapseln - Lesto
@lesto Sicher, einverstanden, ein VPN kann eine nützliche zusätzliche Schicht sein, wenn es nicht wie Magic Security Sauce behandelt wird, wie es viele Admins leider tun. - Craig Ringer


Eine einfache Erweiterung zu Craigs eindrucksvollem Aktionsplan:

Vielleicht benutzt der Benutzer nur einen relativ kleinen Satz von Netzwerkanbietern (zum Beispiel sein Mobilnetzwerkanbieter während der Bewegung, sein Kabelnetzwerk von zu Hause und vom Arbeitsplatz ausgehende IP von der Arbeit).

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

Ein einfaches Unterstützungsszenario:

  1. Ihr Kunde ruft Sie an, "Ich kann mich nicht anmelden".
  2. Das erfährst du mit einem tcpdump -i eth0 -p tcp port 5432 Befehl, woher kommt er?
  3. Mit einer whois 1.2.3.4 Sie können die von dieser IP verwendete IP-Adresse abrufen. 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 Ähnliches) Sie lassen die TCP-Verbindungen mit seinem neuen Subnetz zu.

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


2
2017-09-09 08:59



Interessante Idee, aber das klingt ein wenig fragil. - nishantjr
@nishantjr Natürlich ist es keine eigenständige Lösung, nur eine Möglichkeit, Dinge besser zu machen. - peterh
Ein praktikablerer Ansatz könnte darin bestehen, einzelne ISPs und / oder Länder auf die weiße Liste zu setzen, um dies zu tun, siehe z. stackoverflow.com/questions/16617607/... - Josip Rodin


Hier ist eine ziemlich einfache Fail2ban-Konfiguration für PostgreSQL, die auf dem oben verlinkten HOWTO basiert, aber auf die tatsächliche Arbeit mit Ubuntu-Paketen abgestimmt ist, eine andere Fehlerbedingung erfasst und verschiedene Debug-Meldungen überspringt, um es schneller zu machen:

/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
2018-01-28 10:16





Fail2ban ist ein mächtiges Werkzeug, aber traue nicht, dass ein Filter so funktioniert wie er ist. Testen Sie alle Filter mit dem Failregex-Toolund denken Sie daran, alle Anführungszeichen zu umgehen (zB "admin" wäre "admin"). Als Beispiel, das Testen der folgenden Filter failregex Zeile von meinem /etc/log/postgresql/postgresql-9.3-main.log funktionierte nicht für mich.

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 gab mir

Fehlerquote: 0 insgesamt

Ich musste den Failregex aktualisieren, um dem Protokollformat zu entsprechen.

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 insgesamt

Der Test fail2ban-regex 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 gab mir das folgende positive Ergebnis mit dem aktualisierten Failregex.

Failregex: 169 insgesamt


0
2017-09-20 22:41