実行中のPostgreSQLサーバーがあり、SSLが有効になっているとします。 「標準」のLinuxおよびPostgreSQLツールを使用して、SSL証明書を調べるにはどうすればよいですか?
openssl x509 -text ...
を実行した場合と同様の出力が得られることを期待しています。また、1行または2行のコマンドラインでの回答を期待しているので、パケットスニファを実行する必要はありません。
PostgreSQLサーバーにアクセスできないので、その構成ファイルを直接見ることができません。
スーパーユーザーログインを持っていないため、ssl_cert_file
設定の値を取得できず、その設定でpg_read_file
を取得できません。
PostgreSQLはSSLハンドシェイクをすぐに実行したくないように思われるため、openssl s_client -connect ...
を使用しても機能しません。
psql
のドキュメントをざっと見たところ、起動時にその情報を表示するコマンドラインパラメーターが見つかりませんでした。 (ただし、特定の暗号情報は表示されます)。
OpenSSLのs_client
ツールが1.1.1で-starttls
を使用してPostgresサポートを追加したように見えるため、追加のヘルパースクリプトなしでOpenSSLのコマンドラインツールの全機能を使用できます。
openssl s_client -starttls postgres -connect my.postgres.Host:5432 # etc...
参照:
クレイグ・リンガーのコメントのアイデアに続いて:
1つのオプションは、PostgreSQLプロトコルとのハンドシェイクに
openssl s_client
をパッチすることです。おそらく、カスタム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());
}
}
}
}
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
csdの答え は本当に私を救った。これは、Javaを知らない、またはJavaを忘れた私たちのためのより詳細なウォークスルーです。
サーバーがJavaをコンパイルできることを確認してください。コマンド「which javac」を試してください。「... no javac in ...」のような出力が出る場合は、JDKをインストールする必要があります(JREは機能しませんが、「Java」はありますが「javac」はありません)。
Postgresql-jdbcをまだインストールしていない場合は、インストールします。 RHEL6の場合、コマンドは「yum install postgresql-jdbc」です。 jarファイルがインストールされている場所を見つけます。バージョンごとに1つずつ、いくつかあります。 「/usr/share/Java/postgresql-jdbc3.jar」を使用しました。
Csdのコードをコピーしてデータベース情報を挿入するか(他の回答)、またはこの回答の最後に少し変更したバージョンを使用してください。正確に「ShowPostgreSQLCert.Java」というファイルに保存します。大文字と小文字が区別されます。それ以外の名前を付けると、コンパイルされません。
ShowPostgreSQLCert.Javaファイルのあるディレクトリで、次のコマンドを実行します(必要に応じてpostgresql-jdbc3.jarの場所を変更します): "javac -cp /usr/share/Java/postgresql-jdbc3.jar ShowPostgreSQLCert.Java"。これで、3つの.classファイルが同じディレクトリにあるはずです。
最後に、「Java -cp。:/ usr/share/Java/postgresql-jdbc3.jar ShowPostgreSQLCert」コマンドを実行します。 「。」 「-cp」の後は、現在のディレクトリで.classファイルを探す必要があることを意味します。ここにクラスファイルへのフルパスを挿入できます。パスと.jarファイルの場所の間に「:」を置くことを忘れないでください。
別のマシンでコマンドを実行する必要がある場合は、同じ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());
}
}
}
}
https://stackoverflow.com/questions/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]));
}
}
}
}