web-dev-qa-db-ja.com

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

製品リストを取得するために在庫APIを設定するためにVPNに接続しましたが、問題なく動作します。 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
88
selladurai

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

証明書をファイルに保存したので、これをJVMのトラストストアに追加する必要があります。 JREの場合は$Java_HOME/jre/lib/security/、JDKの場合は$Java_HOME/lib/securityに、Javaに付属のcacertsという名前のファイルがあります。このファイルには、有名な認証局の公開証明書が含まれています。新しい証明書をインポートするには、cacertsへの書き込み権限を持つユーザーとしてkeytoolを実行します。

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

ほとんどの場合、パスワードの入力を求められます。 Javaに同梱されているデフォルトのパスワードはchangeitです。だれもそれを変更しません。これらの比較的簡単な手順を完了すると、安全に通信し、正しいサーバーと正しいサーバーのみと通信していることが保証されます(秘密キーを紛失しない限り)。

129
Ryan Stewart

今、私はこのようにしてこの問題を解決しました、

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を使って必要な証明書をインストールすることが不可能なシナリオでのみ使われるべきです。一時的な証明書を使ったローカルテスト.

15
selladurai

URLに接続しようとしているときはいつでも、

他のサイトのサーバーがhttpsプロトコルで動作しており、証明書に記載されている情報を介して通信することを要求している場合は、次のオプションがあります。

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

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

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

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

  // 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 を参照してください。

9

私はあなたがSSLを使って何かに接続しようとしているが、何かがverisignのようなルート認証局によって検証されていない証明書を提供していると信じています。相手方の鍵またはverisignなどの他のベンダが介入して、提供されている公開鍵が本当に正しいと言うことができます。

すべてのOSはほんの一握りの認証局を信頼しており、小規模な認証発行者は、私が言っていることがわかる場合は、一連の認証者を作る大規模な認証者の1人によって認証される必要があります。

とにかく話を戻します。JavaアプレットとJavaサーバーをプログラムするときによく似た問題を抱えていました(いつかすべてのセキュリティーが機能するようになったことに関する完全なブログ記事を書くことを願っています)。

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

私は約2ヶ月前にこれをしました、そして、今私の上にソースコードを持ってはいけません.. googleを使ってください、そして、あなたはこの問題を解決することができるはずです。あなたが私にメッセージを返すことができないなら、私はあなたにプロジェクトの関連ソースコードを提供することができます..あなたがこれらの例外を引き起こすコードを提供しなかったのでこれがあなたの問題を解決するかどうか知らないでください。さらに、なぜアプレットがServerletsで機能しないのかわからないと思ってアプレットを使って作業していました...

P.S私のオフィスでは外部SSHが無効になっているので、週末までにソースコードを入手することはできません:(

0
Osama Javed

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

  1. SSLの組み込み

    • SSLを取得する

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

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

  2. SSLを無視する

    この#2については、別のstackoverflowウェブサイトの他の回答をご覧ください: SSL検証をインゴットする方法SSL証明書を無視するJavaのエラー

0
Anamika