Come esaminare il certificato SSL del server PostgreSQL?


14

Supponiamo che ci sia un server PostgreSQL in esecuzione e che SSL sia abilitato. Utilizzando gli strumenti "standard" di Linux e PostgreSQL, come posso esaminare il suo certificato SSL?

Spero in un output simile a quello che otterresti dalla corsa openssl x509 -text .... E spero in una risposta dalla riga di comando a una o due righe, quindi non devo ricorrere a uno sniffer di pacchetti.

Non ho accesso al server PostgreSQL, quindi non posso guardare direttamente i suoi file di configurazione.

Non ho un accesso superutente, quindi non riesco a ottenere il valore ssl_cert_filedell'impostazione e quindi pg_read_filesu di esso.

L'uso openssl s_client -connect ...non funziona perché PostgreSQL non sembra voler eseguire subito l'handshake SSL.

Da una rapida occhiata alla psqldocumentazione, non sono riuscito a trovare un parametro della riga di comando che mostri che mostra tali informazioni all'avvio. (Anche se mi mostra alcune informazioni di cifratura.)

Risposte:


7

Sembra che lo s_clientstrumento di OpenSSL abbia aggiunto il supporto Postgres usando -starttlsin 1.1.1, quindi ora puoi usare tutta la potenza degli strumenti da riga di comando di OpenSSL senza script di supporto aggiuntivi:

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

Riferimenti:


10

Seguendo l'idea nel commento di Craig Ringer:

Un'opzione è quella di patch openssl s_clientper l'handshake con il protocollo PostgreSQL. Probabilmente puoi anche farlo con Java, passando un SSLSocketFactory personalizzato a PgJDBC. Non sono sicuro che ci siano opzioni semplici.

... Ho scritto una semplice fabbrica di socket SSL. Ho copiato il codice della stessa NonValidatingFactoryclasse di PgJDBC e ho appena aggiunto il codice per stampare i certificati.

Ecco come appariva, quando tutto è stato detto e fatto:

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());
            }
        }
    }
}

Sei forte. L'ho appena aggiunto a install-cert github.com/spyhunter99/installcert
spia

Grazie mille. Per le persone che non desiderano utilizzare PGSimpleDataSource. Ecco la variante per l'utilizzo della normale configurazione del driver JDBC: 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

Se non vuoi preoccuparti di installare java e compilare e hai già Python, potresti provare questo script Python: https://github.com/thusoy/postgres-mitm/blob/master/postgres_get_server_cert.py

Lo uso per controllare le date del certificato:

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

O per il certificato completo come testo:

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

1
Per usarlo senza installare: curl https://raw.githubusercontent.com/thusoy/postgres-mitm/master/postgres_get_server_cert.py | python - example.com:5432(ma assicurati di cosa esegui in questo modo !!)
Yajo

3

La risposta di CSD mi ha davvero salvato. Ecco una guida più dettagliata per quelli di noi che non conoscono o hanno dimenticato Java.

  1. Assicurati che il tuo server possa compilare java. Prova il comando "quale javac", se viene emesso qualcosa del tipo "... no javac in ...", devi installare un JDK (JRE non funziona, ha "java" ma non "javac").

  2. Installa postgresql-jdbc se non lo hai già. Per RHEL6 il comando è "yum install postgresql-jdbc". Scopri dove sono installati i file jar. Ce ne saranno diversi, uno per ogni versione. Ho usato "/usr/share/java/postgresql-jdbc3.jar".

  3. Copia il codice csd e inserisci le informazioni del database (l'altra risposta), oppure usa la mia versione leggermente modificata alla fine di questa risposta. Salvalo in un file chiamato esattamente "ShowPostgreSQLCert.java". Le maiuscole / minuscole contano, chiamalo in qualsiasi altro modo e non verrà compilato.

  4. Nella directory con il file ShowPostgreSQLCert.java, eseguire il comando seguente (modificare la posizione di postgresql-jdbc3.jar se necessario): "javac -cp /usr/share/java/postgresql-jdbc3.jar ShowPostgreSQLCert.java". Ora dovresti avere 3 file .class nella stessa directory.

  5. Infine, esegui il seguente comando: "java -cp.: / Usr / share / java / postgresql-jdbc3.jar ShowPostgreSQLCert". Il "." dopo "-cp" significa che dovrebbe cercare nella directory corrente i file .class. Puoi inserire qui il percorso completo dei file di classe, ricorda solo di mantenere il ":" tra il percorso e la posizione del file .jar.

  6. Se devi eseguire il comando su un altro computer devi avere installato lo stesso file jar (postgresql-jdbc3.jar), oppure puoi probabilmente semplicemente copiarlo dal server sul quale hai compilato i file .class. Quindi copia i file .class ed esegui il comando da 5. dopo aver modificato i percorsi.

Ho leggermente modificato il codice in modo da poter passare le informazioni del database dalla riga di comando invece di compilarlo nel file .class. Basta eseguirlo senza alcun argomento e verrà visualizzato un messaggio che mostra quali argomenti si aspetta. Il codice csd + modifiche è:

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());
            }
        }
    }
}

1

Ho aggiunto del codice da /programming/3313020/write-x509-certificate-into-pem-formatted-string-in-java per generare i certificati come PEM e ho rimosso la necessità di specificare un db, nome utente o password (non sono necessari per ottenere il certificato).

Usando questo, sono stato in grado di verificare che un riavvio di PostgreSQL sembra purtroppo necessario per passare a un nuovo certificato.

Non essendo uno sviluppatore Java, i miei passaggi per compilare ed eseguire probabilmente non sono così grandi, ma funzionano, purché tu possa trovare un jdbc postgresql

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

Compilare:

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

Correre:

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

Uscita campione:

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:
...

Fonte:

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]));
            }
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.