Bagaimana cara memeriksa sertifikat SSL server PostgreSQL?

14

Misalkan ada server PostgreSQL yang berjalan dan SSL telah diaktifkan. Menggunakan alat "standar" Linux dan PostgreSQL, bagaimana saya bisa memeriksa sertifikat SSL-nya?

Saya berharap untuk hasil yang mirip dengan apa yang akan Anda dapatkan dari menjalankan openssl x509 -text .... Dan saya berharap untuk jawaban baris perintah satu atau dua baris jadi saya tidak perlu menggunakan sniffer paket.

Saya tidak memiliki akses ke server PostgreSQL, jadi saya tidak dapat melihat file konfigurasinya secara langsung.

Saya tidak memiliki login pengguna super, jadi saya tidak bisa mendapatkan nilai ssl_cert_filepengaturan dan kemudian pg_read_filedi atasnya.

Penggunaan openssl s_client -connect ...tidak berfungsi karena PostgreSQL tampaknya tidak ingin segera melakukan handshake SSL.

Dari sekilas melihat psqldokumentasi, saya tidak dapat menemukan parameter baris perintah yang membuatnya menunjukkan informasi itu pada startup. (Meskipun itu menunjukkan padaku informasi sandi tertentu.)

csd
sumber

Jawaban:

6

Sepertinya s_clientalat OpenSSL menambahkan dukungan Postgres menggunakan -starttlsdi 1.1.1, jadi Anda sekarang dapat menggunakan kekuatan penuh alat baris perintah OpenSSL tanpa skrip pembantu tambahan:

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

Referensi:

Adam Batkin
sumber
10

Mengikuti ide dalam komentar Craig Ringer:

Salah satu opsi adalah menambal openssl s_clientuntuk berjabat tangan dengan protokol PostgreSQL. Anda mungkin juga dapat melakukannya dengan Java, dengan mengirimkan SSLSocketFactory kustom ke PgJDBC. Saya tidak yakin ada opsi sederhana.

... Saya menulis pabrik soket SSL sederhana. Saya menyalin kode NonValidatingFactorykelas PgJDBC sendiri dan hanya menambahkan kode untuk mencetak sertifikat.

Begini tampilannya, ketika semuanya dikatakan dan dilakukan:

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
sumber
kamu keren. Baru saja menambahkan ini ke install-cert github.com/spyhunter99/installcert
spy
Awsome, terima kasih banyak. Bagi orang yang tidak ingin menggunakan PGSimpleDataSource. Di sini varian untuk menggunakan pengaturan driver JDBC normal: 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

Jika Anda tidak ingin repot menginstal java dan kompilasi, dan Anda sudah memiliki python, Anda dapat mencoba skrip python ini: https://github.com/thusoy/postgres-mitm/blob/master/postgres_get_server_cert.py

Saya menggunakannya untuk memeriksa tanggal sertifikat:

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

Atau untuk sertifikat lengkap sebagai teks:

postgres_get_server_cert.py example.com:5432 | openssl x509 -noout -text
mivk
sumber
1
Untuk menggunakannya tanpa menginstal: curl https://raw.githubusercontent.com/thusoy/postgres-mitm/master/postgres_get_server_cert.py | python - example.com:5432(tapi pastikan apa yang Anda lakukan dengan cara ini !!)
Yajo
3

Jawaban csd benar-benar menyelamatkan saya. Berikut adalah langkah-langkah lebih rinci bagi kita yang tidak tahu atau lupa java.

  1. Pastikan server Anda dapat mengkompilasi java. Coba perintah "javac mana", jika itu output sesuatu seperti "... tidak javac di ..." maka Anda perlu menginstal JDK (JRE tidak akan berfungsi, itu memiliki "java" tetapi tidak "javac").

  2. Instal postgresql-jdbc jika Anda belum memilikinya. Untuk RHEL6 perintahnya adalah "yum install postgresql-jdbc". Cari tahu di mana file jar diinstal. Akan ada beberapa dari mereka, satu untuk setiap versi. Saya menggunakan "/usr/share/java/postgresql-jdbc3.jar".

  3. Salin kode csd dan masukkan informasi basis data (jawaban lain), atau gunakan versi saya yang sedikit dimodifikasi pada akhir jawaban ini. Simpan di file yang disebut persis "ShowPostgreSQLCert.java". Huruf besar / kecil, sebut saja hal lain dan tidak akan dikompilasi.

  4. Dalam direktori dengan file ShowPostgreSQLCert.java, jalankan perintah berikut (ubah lokasi postgresql-jdbc3.jar jika diperlukan): "javac -cp /usr/share/java/postgresql-jdbc3.jar ShowPostgreSQLCert.java". Anda sekarang harus memiliki 3 file .class di direktori yang sama.

  5. Terakhir, jalankan perintah berikut: "java -cp.: / Usr / share / java / postgresql-jdbc3.jar ShowPostgreSQLCert". "." setelah "-cp" berarti harus mencari di direktori saat ini untuk file .class. Anda dapat memasukkan path lengkap ke file kelas di sini, hanya ingat untuk menjaga ":" antara path dan lokasi file .jar.

  6. Jika Anda perlu menjalankan perintah pada mesin lain, Anda harus menginstal file jar yang sama (postgresql-jdbc3.jar), atau Anda mungkin bisa menyalinnya dari server tempat Anda mengompilasi file .class. Kemudian cukup salin file .class ke atas dan jalankan perintah dari 5. setelah memodifikasi path.

Saya sedikit mengubah kode sehingga Anda dapat meneruskan informasi basis data pada baris perintah alih-alih mengkompilasinya ke file .class. Jalankan saja tanpa argumen dan itu akan menampilkan pesan yang menunjukkan argumen mana yang diharapkannya. kode + modifikasi csd adalah:

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
sumber
1

Saya menambahkan beberapa kode dari /programming/3313020/write-x509-certificate-into-pem-formatted-string-in-java untuk mengeluarkan sertifikat sebagai PEM, dan menghapus kebutuhan untuk menentukan db, nama pengguna atau kata sandi (mereka tidak diperlukan untuk mendapatkan sertifikat).

Dengan menggunakan ini, saya dapat memverifikasi bahwa restart PostgreSQL sayangnya tampaknya perlu untuk beralih ke sertifikat baru.

Bukan menjadi pengembang Java, langkah-langkah saya untuk membangun dan menjalankan mungkin tidak terlalu bagus, tetapi mereka bekerja, selama Anda dapat menemukan jdbc postgresql

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

Untuk mengkompilasi:

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

Untuk berlari:

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

Output sampel:

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

Sumber:

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
sumber