javax.net.ssl.SSLHandshakeExceptionエラーを解決する方法


101

VPNに接続して在庫APIをセットアップし、製品リストを取得したところ、問題なく動作しました。Webサービスから結果を取得したら、UIにバインドします。また、PayPalを私のアプリケーションに統合して、エクスプレスチェックアウトの支払いを行うと、このエラーが発生します。私はバックエンドプロセスにサーブレットを使用しています。誰でもこの問題を修正する方法を言うことができますか?

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

1
私が知りたいこと、その場合の正確なターゲットは...あなたは例外を受け取りますが、ターゲットについての情報は得られません。それはあなたが期待するものとは異なるかもしれません。証明書を持っていますが、まだこの例外が発生します
ante.sabo

回答:


151

まず、接続しようとしているサーバーから公開証明書を取得する必要があります。これは、サーバー管理者に連絡して要求する、OpenSSLを使用してダウンロードする、またはこれはHTTPサーバーのように見えるため、任意のブラウザーでサーバーに接続してページのセキュリティ情報を表示するなど、さまざまな方法で実行できます。 、証明書のコピーを保存します。(Googleは、特定のブラウザーに対して何をすべきかを正確に指示できるはずです。)

証明書をファイルに保存したので、証明書をJVMのトラストストアに追加する必要があります。時$JAVA_HOME/jre/lib/security/のJREまたは$JAVA_HOME/lib/securityJDKのために、名前のファイルがありますcacertsJavaの付属しており、よく知られた証明機関の公開証明書が含まれています、。新しい証明書をインポートするには、cacertsへの書き込み権限を持つユーザーとしてkeytoolを実行します。

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

ほとんどの場合、パスワードを要求します。Javaに付属するデフォルトのパスワードはchangeitです。ほとんど誰もそれを変更しません。これらの比較的単純な手順を完了すると、適切なサーバーおよび適切なサーバーのみと通信していることを確認しながら、安全に通信できます(秘密キーを紛失しない限り)。


12
「機能しない」よりももう少し詳細が必要です。試した内容といくつかのエラー出力で質問を更新してみてください。残念ながら、それは私の就寝時刻を過ぎているので、多分誰かがあなたの質問に答えられるでしょう。これも非常に一般的な状況です。keytool docsなど、オンラインで多くの情報を見つけることができます。
ライアンスチュワート

基本的に私はPayPal証明書を含める必要があります。私はあなたの手順を実行し、証明書も適切な場所に追加されました。それから私はそれが同じエラーを言うアプリを実行しますか?
セラデュライ

実際には問題なくブラウザで動作し、VPNに接続して在庫リストを取得しましたが、PayPalで支払いを行いました。SSLエラーと表示されますが、オフラインデータまたはホットコードデータを使用すると機能します。
セラデュライ

4
@selladurai:paypalの証明書をインポートする必要はありません。cacertsファイルが破損または変更されていない限り、信頼されたルート証明書がすべて含まれている必要があり、paypalの証明書はそれらのいずれかに遡ることができます。あなたはあなたが良いと知っているcacertsのコピーを手に入れ、代わりにそれを試すことを試みるかもしれません。問題が解決しない場合は、実際にはペイパルに接続していない可能性があります。
ライアンスチュワート

@RyanStewartなんとかガラスフィッシュにインポートする必要がありますか?.cerファイルをjavaホームディレクトリのcacertに追加しましたが、glassfishがそれを使用していないように見えるので、エラーが発生します。
2015

15

今私はこの方法でこの問題を解決しました、

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream; 

// Create a trust manager that does not validate certificate chains like the default 

TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
            {
                //No need to implement.
            }
        }
};

// 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 (Exception e) 
{
    System.out.println(e);
}

もちろん、このソリューションはkeytool、一時的な証明書を使用したローカルテストなどを使用して必要な証明書をインストールできないシナリオでのみ使用する必要があります。


52
うわー、私はそれを「修正」と呼ぶのをためらうでしょう。基本的にセキュリティをオフにしました。はい、データは引き続き暗号化されますが、あなたが話していると予想される人と話している保証はありません。正しい解決策は、ターゲットサーバーの公開鍵を取得し、それを接続を行うJVMのトラストストアにインポートすることです。
ライアンスチュワート、

1
適切な解決策については私の答えを参照してください
ライアン・スチュワート

何の例?私の答えはあなたが必要とするすべてのステップを持つべきです。
ライアンスチュワート


3
ここに示されているコードは、開発サーバーに対して非常に単純なテストを作成している場合に役立ちますが、本番環境ではこれに依存しません。
Jason D

12

URLに接続しようとするたびに、

他のサイトのサーバーがhttpsプロトコルで実行されており、証明書で提供される情報を介して通信する必要がある場合は、次のオプションがあります。

1)証明書を要求し(証明書をダウンロード)、この証明書をトラストアにインポートします。Trustore Javaのデフォルトの使用は\ Java \ jdk1.6.0_29 \ jre \ lib \ security \ cacertsにあり、URLへの接続を再試行すると、接続が受け入れられます。

2)通常のビジネスケースでは、組織の内部URLに接続している可能性があり、それらが正しいことがわかっています。そのような場合、それが正しいURLであると信頼します。上記のような場合、特定のURLに接続するための証明書の保存を要求しないコードを使用できます。

ポイント2では、以下の手順に従う必要があります。

1)HttpsURLConnectionのHostnameVerifierを設定するメソッドを以下に記述します。これは、trustStoreを信頼することを意味するすべての場合にtrueを返します。

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2)URLへの接続を試みる前にdoTrustToCertificatesを呼び出す以下のメソッドを記述します

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

この呼び出しは応答コードを返します= 200は接続が成功したことを意味します。

詳細とサンプルの例については、URLを参照してください。


1
Google Playストアはこれを拒否します。彼らは、APKスキャン中にX509Certificateを無視していることを確認します。
Oliver Dixon

0

SSLを使用して何かに接続しようとしているが、ベリサインなどのルート証明機関によって検証されていない証明書が何かによって提供されていると思います。基本的に、安全な接続は、接続しようとしている人が知っている場合にのみ確立できます。取引相手の鍵またはベリサインなどの他のverndorが介入し、提供されている公開鍵が実際に正しいと言うことができます。

すべてのOSが信頼するのは少数の認証局と小規模な証明書発行者であり、大規模な認証機関の1つが認証機関のチェーンを作成し、認証を取得する必要があります。

とにかくポイントに戻って.. JavaアプレットとJavaサーバーをプログラミングするときに同様の問題がありました(うまくいけば、すべてのセキュリティをどのように機能させるかについて完全なブログ投稿を書くでしょう:))

本質的に私がしなければならなかったことは、サーバーから公開鍵を抽出し、それをアプレット内のキーストアに格納することでした。サーバーに接続したときに、このキーストアを使用してトラストファクトリを作成し、そのトラストファクトリでsslを作成しました。接続。JVMの信頼できるホストにキーを追加したり、起動時にデフォルトの信頼ストアを変更したりするなど、別の手順もあります。

私は約2か月前にこれを行いましたが、現在ソースコードはありません。Googleを使用すれば、この問題を解決できるはずです。メッセージを返せず、プロジェクトの関連するソースコードを提供できる場合は、これらの例外の原因となるコードを提供していないため、問題が解決するかどうかはわかりません。さらに、なぜアプレットがサーバーレットで機能しないのかわからないと思ってアプレットで作業していました...

PS私のオフィスでは外部SSHが無効になっているため、週末までにソースコードを取得できません:(


1
PS私はこのJavaコードをオンラインで見つけてサーバーの公開鍵を抽出して保存しているので、グーグルを続けるか、日曜日になるまで待ちます
Osama Javed

0

SSLHandshakeExceptionは2つの方法で解決できます。

  1. SSLの組み込み

    • SSLを取得します(ソースシステム管理者に問い合わせることで、opensslコマンドでダウンロードすることも、ブラウザで証明書をダウンロードすることもできます)。

    • JRE / lib / securityにあるトラストストア(cacerts)に証明書を追加します

    • トラストストアの場所をvm引数で「-Djavax.net.ssl.trustStore =」として提供します

  2. SSLを無視する

    この#2については、別のstackoverflow Webサイトで他の回答を参照してください: JavaでSSL検証エラーを無視してSSL証明書エラーを無視する方法


-8

今私はこの方法でこの問題を解決しました、

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream;
// Create a trust manager that does not validate certificate chains like the 
default TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            //No need to implement. 
        }
    }
};
// 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 (Exception e) {
    System.out.println(e);
}

4
「実装する必要はありません」は完全に完全に正しくありませんSSL接続が安全でなくなりました。これを行わないでください。
ローン侯爵
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.