60

Java を使用して、ssl 経由でサーバーの 1 つに接続しようとしています。ここで多くのオプションを試しましたが、私の最善の試みです:

私は推奨スクリプトで jssecacerts を生成します: http://blogs.oracle.com/andreas/resource/InstallCert.java コマンドで: java InstallCert ssl.someUrl.de changeit

この後、もう一度コマンドを実行しました:

Loading KeyStore jssecacerts...
Opening connection to ssl.someUrl.de:443...
Starting SSL handshake...

No errors, certificate is already trusted

Server sent 1 certificate(s):

 1 Subject EMAILADDRESS=info@plesk.com, CN=plesk, OU=Plesk, O=Parallels, L=Hernd
on, ST=Virginia, C=US
   Issuer  EMAILADDRESS=info@plesk.com, CN=plesk, OU=Plesk, O=Parallels, L=Hernd
on, ST=Virginia, C=US
   sha1    f1 0d 2c 54 05 e1 32 19 a0 52 5e e1 81 6c a3 a5 83 0d dd 67
   md5     f0 b3 be 5e 5f 6e 90 d1 bc 57 7a b2 81 ce 7d 3d

Enter certificate to add to trusted keystore or 'q' to quit: [1]

ファイルをデフォルトのディレクトリにコピーし、Java trustStore に証明書をロードしました

System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files (x86)\\Java\\jre6\\lib\\security\\jssecacerts");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");

それから私は接続しようとします

URL url = new URL("https://ssl.someUrl.de/");
URLConnection conn = url.openConnection();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));

そして、3行目にエラーが発生します:(ssl.someUrl.deに一致する名前が見つかりません)

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching ssl.someUrl.de found

これはデフォルトの plesk 証明書が原因ですか、それとも何か他の問題がありますか?

セットアップ: JRE 6.20、Netbeans 6.8、Windows7 64 ビット

4

9 に答える 9

78

接続しようとしているサーバーの証明書がホスト名と一致していないようです。

HTTPS クライアントは、サーバーに接続するときに、証明書のホスト名がサーバーのホスト名と一致することを確認します。証明書が信頼されているだけでは十分ではありません。通信したいサーバーとも一致する必要があります。(例えとして、パスポートが正当であると信頼している場合でも、正当であると信頼できるパスポートだけでなく、話したい相手のものであることを確認する必要があります。)

HTTP では、これは次のことを確認することによって行われます。

  • 証明書には、ホスト名と一致する DNS サブジェクト代替名 (これは標準の拡張子です) エントリが含まれています。

  • これに失敗すると、サブジェクトの識別名 (必要に応じてメイン名) の最後の CN がホスト名と一致します。(RFC 2818 を参照してください。)

証明書がないと、サブジェクトの別名が何であるかを判断するのは困難です (ただし、ブラウザに接続してその内容を詳しく確認すると、それを見ることができるはずです)。サブジェクトの識別名は次のようです。

EMAILADDRESS=info@plesk.com, CN=plesk, OU=Plesk, O=Parallels, L=Herndon, ST=Virginia, C=US

(したがって、DNS:ssl.someUrl.de でサブジェクト代替名をまだ持っていない場合は、CN=plesk ではなく CN=ssl.someUrl.de にする必要があります。私の推測では、そうではありません。)

HttpsURLConnection.setHostnameVerifier(..)を使用して、ホスト名の検証をバイパスできる場合があります。検証をバイパスするカスタム HostnameVerifier を作成するのはそれほど難しくありませんが、証明書がここで特に関係するものである場合にのみ実行することをお勧めします。SSLSession 引数とその getPeerCertificates() メソッドを使用して取得できるはずです。

(さらに、いずれにせよデフォルト値を使用しているため、javax.net.ssl.* プロパティを設定した方法で設定する必要はありません。)

または、接続しているサーバーとその証明書を制御できる場合は、上記の命名規則に一致するサーバーの証明書を作成できます (サブジェクトの代替名は改善されますが、CN で十分です)。自己署名証明書で名前を付けるのに十分な場合は、その共通名 (CN) が通信しようとしているホスト名であることを確認してください (完全な URL ではなく、ホスト名のみ)。

于 2010-06-22T13:42:15.933 に答える
19

メソッド fixUntrustCertificate() を作成したので、信頼できる CA にないドメインを扱っている場合は、リクエストの前にメソッドを呼び出すことができます。このコードは、java1.4 以降で動作します。この方法はすべてのホストに適用されます。

public void fixUntrustCertificate() throws KeyManagementException, NoSuchAlgorithmException{


        TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }

            }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        // set the  allTrusting verifier
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
于 2015-11-21T18:25:13.440 に答える
1

サーバー名は、証明書の作成中に指定した姓/名と同じである必要があります

于 2013-07-25T13:52:56.343 に答える