Wie überprüfe ich das SSL-Zertifikat des PostgreSQL-Servers?

14

Angenommen, es wird ein PostgreSQL-Server ausgeführt, auf dem SSL aktiviert ist. Wie kann ich mit "normalen" Linux- und PostgreSQL-Tools das SSL-Zertifikat überprüfen?

Ich hoffe auf eine ähnliche Ausgabe wie beim Laufen openssl x509 -text .... Und ich hoffe auf eine ein- oder zweizeilige Befehlszeilenantwort, damit ich nicht auf einen Paket-Sniffer zurückgreifen muss.

Ich habe keinen Zugriff auf den PostgreSQL-Server, daher kann ich die Konfigurationsdateien nicht direkt anzeigen.

Ich habe kein Superuser-Login, daher kann ich den Wert der ssl_cert_fileEinstellung nicht abrufen und dann pg_read_filedarauf zugreifen.

Die Verwendung openssl s_client -connect ...funktioniert nicht, da PostgreSQL den SSL-Handshake nicht sofort ausführen möchte.

Bei einem kurzen Blick auf die psqlDokumentation konnte ich keinen Befehlszeilenparameter finden, mit dem diese Informationen beim Start angezeigt werden. (Obwohl es mir bestimmte Informationen zur Chiffre anzeigt.)

csd
quelle

Antworten:

6

Es sieht so aus, als hätte das OpenSSL- s_clientTool die Postgres-Unterstützung -starttlsin 1.1.1 hinzugefügt , sodass Sie jetzt die volle Leistung der OpenSSL-Befehlszeilentools ohne zusätzliche Hilfsskripte nutzen können:

openssl s_client -starttls postgres -connect my.postgres.host:5432 # etc...

Verweise:

Adam Batkin
quelle
10

Der Idee in Craig Ringers Kommentar folgend:

Eine Möglichkeit ist das Patchen openssl s_clientauf Handshake mit dem PostgreSQL-Protokoll. Sie können dies wahrscheinlich auch mit Java tun, indem Sie eine benutzerdefinierte SSLSocketFactory an PgJDBC übergeben. Ich bin nicht sicher, ob es einfache Optionen gibt.

... ich habe eine einfache SSL Socket Factory geschrieben. Ich habe den Code der PgJDBC-eigenen NonValidatingFactoryKlasse kopiert und gerade den Code zum Drucken der Zertifikate hinzugefügt.

So sah es aus, als alles gesagt und getan wurde:

import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.sql.Connection;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.postgresql.ds.PGSimpleDataSource;
import org.postgresql.ssl.WrappedFactory;

public class ShowPostgreSQLCert {
    public static void main(String[] args) throws Throwable {
        PGSimpleDataSource ds = new PGSimpleDataSource();
        ds.setServerName( ... );
        ds.setSsl(true);
        ds.setUser( ... );
        ds.setDatabaseName( ... );
        ds.setPassword( ... );
        ds.setSslfactory(DumperFactory.class.getName());
        try (Connection c = ds.getConnection()) { }
    }

    public static class DumperFactory extends WrappedFactory {
        public DumperFactory(String arg) throws GeneralSecurityException {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { new DumperTM() }, null);
            _factory = ctx.getSocketFactory();
        }
    }

    public static class DumperTM implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        public void checkClientTrusted(X509Certificate[] certs, String authType) { }
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            for (int i=0; i<certs.length; ++i) {
                System.out.println("Cert " + (i+1) + ":");
                System.out.println("    Subject: " + certs[i].getSubjectX500Principal().getName());
                System.out.println("    Issuer: " + certs[i].getIssuerX500Principal().getName());
            }
        }
    }
}
csd
quelle
du rockst Gerade hinzugefügt, um zu installieren-cert github.com/spyhunter99/installcert
Spion
Ehrfürchtig vielen Dank. Für Benutzer, die PGSimpleDataSource nicht verwenden möchten. Hier die Variante zur Verwendung des normalen JDBC-Treiber-Setups: String connectionURL = "jdbc:postgresql://server:62013/dbname"; Properties props = new Properties(); props.setProperty("user", "username"); props.setProperty("password", "password"); props.setProperty("ssl", "true"); props.setProperty("sslfactory", DumperFactory.class.getName()); Connection con = null; // Load the Driver class. Class.forName("org.postgresql.Driver"); con = DriverManager.getConnection(connectionURL, props);
Markus
7

Wenn Sie sich nicht um die Installation von Java und das Kompilieren kümmern möchten und bereits über Python verfügen, können Sie dieses Python-Skript ausprobieren: https://github.com/thusoy/postgres-mitm/blob/master/postgres_get_server_cert.py

Ich benutze es, um Zertifikatdaten zu überprüfen:

postgres_get_server_cert.py example.com:5432 | openssl x509 -noout -dates

Oder für das vollständige Zertifikat als Text:

postgres_get_server_cert.py example.com:5432 | openssl x509 -noout -text
mivk
quelle
1
So verwenden Sie es ohne Installation: curl https://raw.githubusercontent.com/thusoy/postgres-mitm/master/postgres_get_server_cert.py | python - example.com:5432(
Achten
3

Die Antwort von csd hat mich wirklich gerettet. Hier ist eine detailliertere Anleitung für diejenigen von uns, die Java nicht kennen oder vergessen haben.

  1. Stellen Sie sicher, dass Ihr Server Java kompilieren kann. Versuchen Sie den Befehl "which javac", wenn er so etwas wie "... no javac in ..." ausgibt, müssen Sie ein JDK installieren (JRE funktioniert nicht, es hat "java", aber nicht "javac").

  2. Installieren Sie postgresql-jdbc, falls Sie es noch nicht haben. Für RHEL6 lautet der Befehl "yum install postgresql-jdbc". Finden Sie heraus, wo die JAR-Dateien installiert sind. Es wird mehrere davon geben, eine für jede Version. Ich habe "/usr/share/java/postgresql-jdbc3.jar" verwendet.

  3. Kopieren Sie den Code von csd und fügen Sie die Datenbankinformationen (die andere Antwort) ein oder verwenden Sie meine leicht geänderte Version am Ende dieser Antwort. Speichern Sie es in einer Datei mit dem Namen "ShowPostgreSQLCert.java". Groß- / Kleinschreibung ist wichtig, nennen Sie es etwas anderes und es wird nicht kompiliert.

  4. Führen Sie im Verzeichnis mit der Datei ShowPostgreSQLCert.java den folgenden Befehl aus (ändern Sie den Speicherort von postgresql-jdbc3.jar, falls erforderlich): "javac -cp /usr/share/java/postgresql-jdbc3.jar ShowPostgreSQLCert.java". Sie sollten jetzt 3 .class-Dateien in demselben Verzeichnis haben.

  5. Führen Sie abschließend den folgenden Befehl aus: "java -cp.: /Usr/share/java/postgresql-jdbc3.jar ShowPostgreSQLCert". Das "." Nach "-cp" bedeutet, dass im aktuellen Verzeichnis nach den .class-Dateien gesucht werden soll. Sie können hier den vollständigen Pfad zu den Klassendateien einfügen. Denken Sie jedoch daran, das ":" zwischen dem Pfad und dem Speicherort der JAR-Datei einzuhalten.

  6. Wenn Sie den Befehl auf einem anderen Computer ausführen müssen, muss dieselbe JAR-Datei installiert sein (postgresql-jdbc3.jar), oder Sie können sie wahrscheinlich einfach von dem Server kopieren, auf dem Sie die .class-Dateien kompiliert haben. Kopieren Sie dann einfach die .class-Dateien und führen Sie den Befehl ab 5. aus, nachdem Sie die Pfade geändert haben.

Ich habe den Code geringfügig geändert, damit Sie Datenbankinformationen in der Befehlszeile übergeben können, anstatt sie in die .class-Datei zu kompilieren. Führen Sie es einfach ohne Argumente aus, und es wird eine Meldung mit den erwarteten Argumenten angezeigt. Der Code von csd + Modifikationen ist:

import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.sql.Connection;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.postgresql.ds.PGSimpleDataSource;
import org.postgresql.ssl.WrappedFactory;

public class ShowPostgreSQLCert {
    public static void main(String[] args) throws Throwable {
        PGSimpleDataSource ds = new PGSimpleDataSource();
        if( args.length != 4 ) {
            System.out.println("Not enough arguments. Usage: ShowPostgreSQLCert ServerName User DatabaseName Password");
            System.exit(1);
        }
        ds.setServerName( args[0] );
        ds.setSsl(true);
        ds.setUser( args[1] );
        ds.setDatabaseName( args[2] );
        ds.setPassword( args[3] );
        ds.setSslfactory(DumperFactory.class.getName());
        try (Connection c = ds.getConnection()) { }
    }

    public static class DumperFactory extends WrappedFactory {
        public DumperFactory(String arg) throws GeneralSecurityException {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { new DumperTM() }, null);
            _factory = ctx.getSocketFactory();
        }
    }

    public static class DumperTM implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        public void checkClientTrusted(X509Certificate[] certs, String authType) { }
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            for (int i=0; i<certs.length; ++i) {
                System.out.println("Cert " + (i+1) + ":");
                System.out.println("    Subject: " + certs[i].getSubjectX500Principal().getName());
                System.out.println("    Issuer: " + certs[i].getIssuerX500Principal().getName());
            }
        }
    }
}
Vidarsk
quelle
1

Ich habe Code von /programming/3313020/write-x509-certificate-into-pem-formatted-string-in-java hinzugefügt, um die Zertifikate als PEM auszugeben, und die Angabe einer Datenbank wurde entfernt. Benutzername oder Passwort (sie werden nicht benötigt, um das Zertifikat zu erhalten).

Auf diese Weise konnte ich feststellen, dass ein Neustart von PostgreSQL leider nicht erforderlich ist, um auf ein neues Zertifikat umzusteigen.

Da ich kein Java-Entwickler bin, sind meine Schritte zum Erstellen und Ausführen wahrscheinlich nicht so großartig, aber sie funktionieren, solange Sie eine postgresql-JDBC finden

# locate postgresql | grep jar
/path/to/a/lib/postgresql-9.1-901-1.jdbc4.jar   <-- this one will do
...

Kompilieren:

javac -cp /path/to/a/lib/postgresql-9.1-901-1.jdbc4.jar ./ShowPostgreSQLCert.java

Laufen:

java -cp /path/to/a/lib/postgresql-9.1-901-1.jdbc4.jar:. ShowPostgreSQLCert 127.0.0.1

Beispielausgabe:

Cert 1:
    Subject: CN=...
    Issuer: CN=...
    Not Before: Fri Oct 21 11:14:06 NZDT 2016
    Not After: Sun Oct 21 11:24:00 NZDT 2018
-----BEGIN CERTIFICATE-----
MIIHEjCCBfqgAwIBAgIUUbiRZjruNAEo2j1QPqBh6GzcNrwwDQYJKoZIhvcNAQEL
...
IcIXcVQxPzVrpIDT5G6jArVt+ERLEWs2V09iMwY7//CQb0ivpVg=
-----END CERTIFICATE-----

Cert 2:
...

Quelle:

import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.sql.Connection;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.postgresql.ds.PGSimpleDataSource;
import org.postgresql.ssl.WrappedFactory;

import javax.xml.bind.DatatypeConverter;
import java.security.cert.X509Certificate;
import java.io.StringWriter;

public class ShowPostgreSQLCert {
    public static void main(String[] args) throws Throwable {
        PGSimpleDataSource ds = new PGSimpleDataSource();
        if( args.length != 1 ) {
            System.out.println("Not enough arguments.");
            System.out.println("Usage: ShowPostgreSQLCert ServerName");
            System.exit(1);
        }
        ds.setServerName( args[0] );
        ds.setSsl(true);
        ds.setUser( "" );
        ds.setDatabaseName( "" );
        ds.setPassword( "" );
        ds.setSslfactory(DumperFactory.class.getName());
        try (Connection c = ds.getConnection()) { }
        catch (org.postgresql.util.PSQLException e) {
            // Don't actually want to login
        }
    }

    public static class DumperFactory extends WrappedFactory {
        public DumperFactory(String arg) throws GeneralSecurityException {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { new DumperTM() }, null);
            _factory = ctx.getSocketFactory();
        }
    }

    public static String certToString(X509Certificate cert) {
        StringWriter sw = new StringWriter();
        try {
            sw.write("-----BEGIN CERTIFICATE-----\n");
            sw.write(DatatypeConverter.printBase64Binary(cert.getEncoded()).replaceAll("(.{64})", "$1\n"));
            sw.write("\n-----END CERTIFICATE-----\n");
        } catch (java.security.cert.CertificateEncodingException e) {
            e.printStackTrace();
        }
        return sw.toString();
    }

    public static class DumperTM implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        public void checkClientTrusted(X509Certificate[] certs, String authType) { }
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            for (int i=0; i<certs.length; ++i) {

                System.out.println("Cert " + (i+1) + ":");
                System.out.println("    Subject: " + certs[i].getSubjectX500Principal().getName());
                System.out.println("    Issuer: " + certs[i].getIssuerX500Principal().getName());
                System.out.println("    Not Before: " + certs[i].getNotBefore().toString());
                System.out.println("    Not After: " + certs[i].getNotAfter().toString());

                System.out.println(certToString(certs[i]));
            }
        }
    }
}
Cameron Kerr
quelle