Як перевірити сертифікат SSL сервера PostgreSQL?


14

Припустимо, працює сервер PostgreSQL, на якому ввімкнено SSL. Як "стандартні" інструменти Linux та PostgreSQL можна перевірити його сертифікат SSL?

Я сподіваюся на вихід, подібний до того, який ви отримаєте від запуску openssl x509 -text .... І я сподіваюсь на відповідь командного рядка з одним або двома лайнерами, тому мені не доведеться вдаватися до запуску sniffer пакетів.

У мене немає доступу до сервера PostgreSQL, тому я не можу переглядати файли його конфігурації безпосередньо.

У мене немає входу суперпользователя, тому я не можу отримати значення ssl_cert_fileналаштування, а потім pg_read_fileна ньому.

Використання openssl s_client -connect ...не працює, тому що PostgreSQL, схоже, не хоче відразу робити рукостискання SSL.

Швидкий огляд psqlдокументації я не зміг знайти параметр командного рядка, завдяки якому він відображає інформацію про запуск. (Хоча це і показує мені певну інформацію про шифр.)

Відповіді:


7

Схоже, s_clientінструмент OpenSSL додав підтримку Postgres за допомогою -starttls1.1.1, тому тепер ви можете використовувати всю потужність інструментів командного рядка OpenSSL без додаткових допоміжних скриптів:

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

Список літератури:


10

Слідуючи ідеї у коментарі Крейга Рінгера:

Один із варіантів - це патч openssl s_clientдля рукостискання з протоколом PostgreSQL. Можливо, ви також можете це зробити з Java, передавши користувальницький SSLSocketFactory PgJDBC. Я не впевнений, що є прості варіанти.

... Я написав просту фабрику розеток SSL. Я скопіював код власного NonValidatingFactoryкласу PgJDBC і просто додав код для друку сертифікатів.

Ось як це виглядало, коли все було сказано і зроблено:

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

ти рок. Щойно додав це, щоб встановити-cert github.com/spyhunter99/installcert
шпигун

Велике спасибі велике. Для людей, які не хочуть використовувати PGSimpleDataSource. Ось варіант використання нормальної установки драйверів 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

Якщо ви не хочете займатись встановленням Java та компіляцією, а у вас вже є python, ви можете спробувати цей сценарій python: https://github.com/thusoy/postgres-mitm/blob/master/postgres_get_server_cert.py

Я використовую його для перевірки дати сертифікату:

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

Або для повного документа як тексту:

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

1
Щоб використовувати його без встановлення: curl https://raw.githubusercontent.com/thusoy/postgres-mitm/master/postgres_get_server_cert.py | python - example.com:5432(але будьте впевнені, що ви виконаєте таким чином !!)
Yajo

3

Відповідь CDD мене справді врятувала. Ось більш детальна інформація для тих, хто не знає або забув Java.

  1. Переконайтеся, що ваш сервер може компілювати Java. Спробуйте команду "який javac", якщо вона видає щось на кшталт "... немає javac в ...", тоді вам потрібно встановити JDK (JRE не буде працювати, він має "java", але не "javac").

  2. Встановіть postgresql-jdbc, якщо у вас його ще немає. Для RHEL6 командою є "yum install postgresql-jdbc". З’ясуйте, де встановлені файли jar. Їх буде кілька, по одному для кожної версії. Я використовував "/usr/share/java/postgresql-jdbc3.jar".

  3. Скопіюйте код csd та вставте інформацію бази даних (інша відповідь) або скористайтеся моєю трохи зміненою версією наприкінці цієї відповіді. Збережіть його у файлі, який називається точно "ShowPostgreSQLCert.java". Верхня / мала література має значення, називайте це все інше, і він не збирається.

  4. У каталозі з файлом ShowPostgreSQLCert.java запустіть таку команду (за потреби змініть розташування postgresql-jdbc3.jar): "javac -cp /usr/share/java/postgresql-jdbc3.jar ShowPostgreSQLCert.java". Тепер у вас є 3 файли .class в одному каталозі.

  5. Нарешті, запустіть таку команду: "java -cp .: / usr / share / java / postgresql-jdbc3.jar ShowPostgreSQLCert". "". після "-cp" означає, що він повинен шукати у поточному режимі файли .class. Тут можна вставити повний шлях до файлів класу, просто не забудьте зберегти ":" між контуром і розташуванням .jar-файлу.

  6. Якщо вам потрібно запустити команду на іншій машині, вам потрібно встановити один і той самий файл jar (postgresql-jdbc3.jar), або ви, ймовірно, можете просто скопіювати його з сервера, на якому складено файли .class. Потім просто скопіюйте файли .class та запустивши команду з 5. після зміни шляхів.

Я трохи змінив код, щоб ви могли передавати інформацію бази даних в командному рядку, а не компілювати його у файл .class. Просто запустіть його без жодних аргументів, і воно покаже повідомлення, яке аргументи очікує. Код csd + модифікації:

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

Я додав код з /programming/3313020/write-x509-certificate-into-pem-formatted-string-in-java для виведення сертифікатів як PEM, і усунув необхідність вказувати db, ім'я користувача або пароль (вони не потрібні для отримання сертифіката).

Використовуючи це, я зміг переконатися, що перезапуск PostgreSQL, на жаль, здається необхідним для переходу на новий сертифікат.

Не будучи розробником Java, мої кроки зі створення та запуску, ймовірно, не такі великі, але вони працюють, доки ви зможете знайти postgresql jdbc

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

Для складання:

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

Бігти:

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

Вибірка зразка:

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

Джерело:

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]));
            }
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.