PostgreSQL 서버의 SSL 인증서를 검사하는 방법은 무엇입니까?


14

PostgreSQL 서버가 실행 중이고 SSL이 활성화되어 있다고 가정하십시오. "표준"Linux 및 PostgreSQL 도구를 사용하여 SSL 인증서를 검사하려면 어떻게해야합니까?

나는 당신이 running에서 얻을 수있는 것과 비슷한 출력을 기대하고 있습니다 openssl x509 -text .... 그리고 하나 또는 두 개의 라이너 명령 줄 답변을 원하므로 패킷 스니퍼를 실행하지 않아도됩니다.

PostgreSQL 서버에 액세스 할 수 없으므로 구성 파일을 직접 볼 수 없습니다.

수퍼 유저 로그인이 없으므로 ssl_cert_file설정 값을 얻을 수 없습니다 pg_read_file.

openssl s_client -connect ...PostgreSQL이 SSL 핸드 셰이크를 바로 원하지 않는 것이므로 사용 이 작동하지 않습니다.

psql설명서를 살펴보면 시작시 해당 정보를 표시하는 명령 줄 매개 변수를 찾을 수 없습니다. (그러나 그것은 특정 암호 정보를 보여줍니다.)

답변:


7

OpenSSL의 s_client도구 -starttls가 1.1.1에서 Postgres 지원을 추가 한 것처럼 보이 므로 이제 추가 도우미 스크립트없이 OpenSSL의 명령 줄 도구를 모두 사용할 수 있습니다.

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

참고 문헌 :


10

Craig Ringer의 의견에 따르면 :

한 가지 옵션은 openssl s_clientPostgreSQL 프로토콜로 핸드 셰이크 하도록 패치 하는 것입니다. 사용자 정의 SSLSocketFactory를 PgJDBC에 전달하여 Java로도 가능합니다. 간단한 옵션이 있는지 확실하지 않습니다.

... 간단한 SSL 소켓 팩토리를 작성했습니다. PgJDBC 자체 NonValidatingFactory클래스 의 코드를 복사 하고 인증서를 인쇄하는 코드를 추가했습니다.

모든 것이 말되고 완료되었을 때의 모습은 다음과 같습니다.

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에 추가
spy

정말 고마워 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 설치 및 컴파일에 신경 쓰지 않고 이미 파이썬을 가지고 있다면이 파이썬 스크립트를 사용해보십시오 : 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

csd의 답변이 실제로 저를 구했습니다. 여기에 Java를 모르거나 잊어 버린 사람들을위한 더 자세한 연습이 있습니다.

  1. 서버가 Java를 컴파일 할 수 있는지 확인하십시오. "which javac"명령을 시도하십시오. "... no javac in ..."와 같은 것을 출력하면 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]));
            }
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.