Làm cách nào để kiểm tra chứng chỉ SSL của máy chủ PostgreSQL?


14

Giả sử có một máy chủ PostgreSQL đang chạy và nó đã bật SSL. Sử dụng các công cụ Linux và PostgreQuery "tiêu chuẩn", làm cách nào tôi có thể kiểm tra chứng chỉ SSL của nó?

Tôi hy vọng đầu ra tương tự như những gì bạn sẽ nhận được từ việc chạy openssl x509 -text .... Và tôi hy vọng câu trả lời dòng lệnh một hoặc hai lớp để tôi không phải dùng đến một trình thám thính gói.

Tôi không có quyền truy cập vào máy chủ PostgreSQL, vì vậy tôi không thể xem trực tiếp các tệp cấu hình của nó.

Tôi không có thông tin đăng nhập siêu người dùng, vì vậy tôi không thể nhận được giá trị của ssl_cert_filecài đặt và sau đó pg_read_filetrên đó.

Việc sử dụng openssl s_client -connect ...không hoạt động vì PostgreSQL dường như không muốn thực hiện bắt tay SSL ngay lập tức.

Từ một cái nhìn nhanh vào psqltài liệu, tôi không thể tìm thấy một tham số dòng lệnh làm cho nó hiển thị thông tin đó khi khởi động. (Mặc dù nó cho tôi thấy một số thông tin mật mã.)

Câu trả lời:


6

Có vẻ như s_clientcông cụ của OpenSSL đã thêm hỗ trợ Postgres bằng -starttls1.1.1, vì vậy giờ đây bạn có thể sử dụng toàn bộ sức mạnh của các công cụ dòng lệnh của OpenSSL mà không cần các tập lệnh trợ giúp bổ sung:

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

Người giới thiệu:


10

Theo ý tưởng trong bình luận của Craig Ringer:

Một tùy chọn là vá openssl s_clientđể bắt tay với giao thức PostgreSQL. Bạn có thể cũng có thể làm điều đó với Java, bằng cách chuyển SSLSocketFactory tùy chỉnh cho PGJDBC. Tôi không chắc có bất kỳ lựa chọn đơn giản nào.

... Tôi đã viết một nhà máy ổ cắm SSL đơn giản. Tôi đã sao chép mã của NonValidatingFactorylớp riêng của PGJDBC và chỉ cần thêm mã để in chứng chỉ.

Đây là những gì nó trông giống như, khi tất cả đã được nói và thực hiện:

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

bạn đá Chỉ cần thêm phần này vào install-cert github.com/spyhunter99/installcert
gián điệp

Awsome cảm ơn rất nhiều. Đối với những người không muốn sử dụng PGSimpleDataSource. Ở đây biến thể để sử dụng thiết lập trình điều khiển JDBC bình thường: 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

Nếu bạn không muốn cài đặt java và biên dịch, và bạn đã có python, bạn có thể thử tập lệnh python này: https://github.com/thusoy/postgres-mitm/blob/master/postgres_get_server_cert.py

Tôi sử dụng nó để kiểm tra ngày chứng nhận:

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

Hoặc cho chứng chỉ đầy đủ dưới dạng văn bản:

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

1
Để sử dụng nó mà không cần cài đặt: curl https://raw.githubusercontent.com/thusoy/postgres-mitm/master/postgres_get_server_cert.py | python - example.com:5432(nhưng hãy chắc chắn về những gì bạn thực hiện theo cách này !!)
Yajo

3

Câu trả lời của csd thực sự đã cứu tôi. Dưới đây là hướng dẫn chi tiết hơn cho những người trong chúng ta không biết hoặc đã quên java.

  1. Hãy chắc chắn rằng máy chủ của bạn có thể biên dịch java. Hãy thử lệnh "which javac", nếu nó xuất ra cái gì đó như "... không có javac trong ..." thì bạn cần cài đặt JDK (JRE sẽ không hoạt động, nó có "java" chứ không phải "javac").

  2. Cài đặt postgresql-jdbc nếu bạn chưa có nó. Đối với RHEL6, lệnh này là "yum install postgresql-jdbc". Chỉ ra nơi các tập tin jar được cài đặt. Sẽ có một vài trong số họ, một cho mỗi phiên bản. Tôi đã sử dụng "/usr/share/java/postgresql-jdbc3.jar".

  3. Sao chép mã của csd và chèn thông tin cơ sở dữ liệu (câu trả lời khác) hoặc sử dụng phiên bản sửa đổi một chút của tôi ở cuối câu trả lời này. Lưu nó trong một tệp có tên chính xác là "ShowPostgreSQLCert.java". Vấn đề chữ hoa / chữ thường, gọi nó là bất cứ thứ gì khác và nó sẽ không được biên dịch.

  4. Trong thư mục chứa tệp ShowPostgreQueryCert.java, hãy chạy lệnh sau (sửa đổi vị trí của postgresql-jdbc3.jar nếu cần): "javac -cp /usr/share/java/postgresql-jdbc3.jar ShowPostgre.j Bây giờ bạn sẽ có 3 tệp. Class trong cùng một thư mục.

  5. Cuối cùng, chạy lệnh sau: "java -cp .: / Usr / share / java / postgresql-jdbc3.jar ShowPostgreQueryCert". Các "." sau "-cp" có nghĩa là nó sẽ tìm trong thư mục hiện tại cho các tệp. class. Bạn có thể chèn đường dẫn đầy đủ vào các tệp lớp ở đây, chỉ cần nhớ giữ dấu ":" giữa đường dẫn và vị trí của tệp .jar.

  6. Nếu bạn cần chạy lệnh trên một máy khác, bạn cần cài đặt cùng một tệp jar (postgresql-jdbc3.jar) hoặc có thể bạn chỉ cần sao chép nó từ máy chủ mà bạn đã biên dịch các tệp. Class trên đó. Sau đó, chỉ cần sao chép các tập tin. Class và chạy lệnh từ 5. sau khi sửa đổi các đường dẫn.

Tôi đã sửa đổi một chút mã để bạn có thể truyền thông tin cơ sở dữ liệu trên dòng lệnh thay vì biên dịch nó vào tệp. Class. Chỉ cần chạy nó mà không có bất kỳ đối số nào và nó sẽ hiển thị một thông báo hiển thị những đối số mà nó mong đợi. mã + sửa đổi của csd là:

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

Tôi đã thêm một số mã từ /programming/3313020/write-x509-certert-into-pem-formatted-opes-in-java để xuất chứng chỉ dưới dạng PEM và loại bỏ nhu cầu chỉ định db, tên người dùng hoặc mật khẩu (không cần thiết để lấy chứng chỉ).

Sử dụng điều này, tôi đã có thể xác minh rằng việc khởi động lại PostgreSQL có vẻ không cần thiết để chuyển sang chứng chỉ mới.

Không phải là một nhà phát triển Java, các bước để xây dựng và chạy của tôi có thể không tuyệt vời lắm, nhưng chúng hoạt động, miễn là bạn có thể tìm thấy một jdbc postgresql

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

Để biên dịch:

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

Chạy:

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

Đầu ra mẫu:

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

Nguồn:

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]));
            }
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.