245

よくある質問のように見えますが、どこにも明確な指示が見つかりませんでした。

おそらく自己署名 (または期限切れ) の証明書を使用してサーバーに接続しようとしている Java コードがあります。コードは次のエラーを報告します。

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught 
when processing request: sun.security.validator.ValidatorException: PKIX path 
building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

私が理解しているように、keytoolを使用して、この接続を許可してもよいことを Java に伝える必要があります。

この問題を解決するためのすべての手順は、私が次のような keytool に完全に習熟していることを前提としています。

サーバーの秘密鍵を生成し、キーストアにインポートします

詳細な手順を投稿できる人はいますか?

UNIX を実行しているので、bash スクリプトが最適です。

重要かどうかはわかりませんが、コードは jboss で実行されます。

4

14 に答える 14

334

ここには基本的に2つのオプションがあります。自己署名証明書をJVMトラストストアに追加するか、クライアントを次のように構成します。

オプション1

ブラウザから証明書をエクスポートし、JVMトラストストアにインポートします(信頼の鎖を確立するため)。

<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit 

オプション2

証明書の検証を無効にする:

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { 
    new X509TrustManager() {     
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            return new X509Certificate[0];
        } 
        public void checkClientTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
            } 
        public void checkServerTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    } 
}; 

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
} 
// Now you can access an https URL without having the certificate in the truststore
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) {
} 

オプション#2はまったくお勧めしません。トラストマネージャーを無効にすると、SSLの一部が無効になり、中間者攻撃に対して脆弱になります。オプション#1を優先するか、さらに良いことに、サーバーに、よく知られているCAによって署名された「実際の」証明書を使用させます。

于 2010-05-23T23:26:25.050 に答える
30

すべての証明書を信頼するよりも優れた方法があります。TrustStore特定の証明書を明確に信頼する を作成し、これを使用しSSLContextて を取得してSSLSocketFactoryに設定するを作成しますHttpsURLConnection。完全なコードは次のとおりです。

File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
// Or if the crt-file is packaged into a jar file:
// CertificateFactory.getInstance("X.509").generateCertificate(this.class.getClassLoader().getResourceAsStream("server.crt"));


KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

KeyStoreまたは、ファイルから直接ロードするか、信頼できるソースから X.509 証明書を取得することもできます。

このコードでは、証明書はcacerts使用されないことに注意してください。これHttpsURLConnectionは、この特定の証明書のみを信頼します。

于 2019-07-15T20:39:04.930 に答える
10

私はこの問題を、現在のデフォルトの JVM トラステッド ホストの一部ではない証明書プロバイダーに突き止めましたJDK 8u74。プロバイダーはwww.identrust.comですが、接続しようとしていたドメインではありませんでした。そのドメインは、このプロバイダーから証明書を取得していました。クロスルートは、JDK/JRE のデフォルト リストで信頼をカバーしますか?を参照してください。-- いくつかのエントリを読んでください。Let's Encrypt をサポートするブラウザとオペレーティング システムも参照してください。

そこで、興味のあるドメインに接続するためにidentrust.com、次の手順を実行しました。基本的に、identrust.com ( DST Root CA X3) 証明書を JVM によって信頼されるように取得する必要がありました。次のように Apache HttpComponents 4.5 を使用してそれを行うことができました。

1: Certificate Chain Download Instructionsで indettrust から証明書を取得します。DST ルート CA X3リンクをクリックします。

2: 文字列を「DST Root CA X3.pem」という名前のファイルに保存します。ファイルの先頭と末尾に「-----BEGIN CERTIFICATE-----」と「-----END CERTIFICATE-----」の行を必ず追加してください。

3: 次のコマンドを使用して、Java キーストア ファイル cacerts.jks を作成します。

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4: 生成された cacerts.jks キーストアを java/(maven) アプリケーションの resources ディレクトリにコピーします。

5: 次のコードを使用してこのファイルをロードし、Apache 4.5 HttpClient に添付します。indetrust.comこれにより、 util oracleから発行された証明書を持つすべてのドメインの問題が解決され、JRE のデフォルト キーストアに証明書が含まれます。

SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
                new TrustSelfSignedStrategy())
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

プロジェクトがビルドされると、cacerts.jks がクラスパスにコピーされ、そこからロードされます。現時点では、他の SSL サイトに対してテストを行っていませんが、上記のコードがこの証明書で「チェーン」されている場合は、それらも機能しますが、わかりません。

参照:カスタム SSL コンテキストおよびJava HttpsURLConnection で自己署名証明書を受け入れるにはどうすればよいですか?

于 2016-04-19T01:45:20.080 に答える
2

「彼ら」が自己署名証明書を使用している場合、サーバーを使用可能にするために必要な手順を実行するのは彼ら次第です。具体的には、信頼できる方法で証明書をオフラインで提供することを意味します。だから彼らにそれをさせてください。次に、JSSE リファレンス ガイドで説明されているように、keytool を使用してそれをトラストストアにインポートします。ここに投稿された安全でない TrustManager についても考えないでください。

編集私がここに書いたことを実際に読んでいないことが明らかな17人(!)の反対投票者と以下の多数のコメント者のために、これは自己署名証明書に対する非難ではありません。正しく実装されていれば 、自己署名証明書に問題はありません。ただし、それらを実装する正しい方法は、認証に使用される認証されていないチャネルを介してではなく、オフライン プロセスを介して証明書を安全に配信することです。確かにこれは明らかですか?何千もの支店を持つ銀行から私の会社まで、私がこれまでに働いたことのあるすべてのセキュリティ意識の高い組織にとって、これは明らかです。すべてを信頼するクライアント側コードベースの「ソリューション」絶対に誰かによって署名された自己署名証明書、または自らを CA として設定している任意の団体を含む証明書は、事実上安全ではありません。セキュリティで遊んでいるだけです。無意味です。あなたはプライベートで、改ざん防止、返信防止、インジェクション防止の会話をしています... 誰かと。誰でも。真ん中の男。なりすまし。誰でも。プレーンテキストをそのまま使用することもできます。

于 2010-05-24T08:08:01.537 に答える