如何解决javax.net.ssl.SSLHandshakeException错误?

sel*_*rai 93 java vpn servlets paypal sslhandshakeexception

我与VPN连接以设置库存API以获取产品列表,它工作正常.一旦我从Web服务获得结果并且我绑定到UI.此外,当我拨打电话付款时,我还将PayPal与我的应用程序集成,以便快速结账.我遇到了这个错误.我使用servlet进行后端处理.任何人都可以说如何解决这个问题?

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
Run Code Online (Sandbox Code Playgroud)

Rya*_*art 140

首先,您需要从您尝试连接的服务器获取公共证书.这可以通过多种方式完成,例如联系服务器管理员并要求它,使用OpenSSL下载它,或者,因为这似乎是HTTP服务器,使用任何浏览器连接到它,查看页面的安全信息,并保存证书的副本.(Google应该能够准确地告诉您如何为您的特定浏览器做些什么.)

现在您已将证书保存在文件中,您需要将其添加到JVM的信任库.在$JAVA_HOME/jre/lib/security/对的JRE或$JAVA_HOME/lib/security对JDK中,有一个名为文件cacerts,附带了Java和含有众所周知的核准当局的公证书.要导入新证书,请以有权写入cacerts的用户身份运行keytool:

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>
Run Code Online (Sandbox Code Playgroud)

它很可能会要求您输入密码.Java附带的默认密码是changeit.几乎没有人改变它.完成这些相对简单的步骤后,您将安全地进行通信,并保证您正在与正确的服务器和正确的服务器通信(只要它们不会丢失其私钥).

  • 我需要比"不工作"更多的细节.尝试使用您尝试的内容和一些错误输出更新您的问题.不幸的是,它已经过了我的睡觉时间,所以也许别人可以回答你的问题.这也是一种非常普遍的情况.您可以在线找到大量信息,包括[keytool docs](http://download.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html). (12认同)
  • @selladurai:您不需要为paypal导入证书.除非您的cacerts文件已损坏或修改,否则它应包含所有受信任的根证书,并且paypal的证书应该能够追溯到其中一个.你可能会尝试获得一份你知道很好的cacerts副本,然后尝试使用它.如果问题仍然存在,那么您可能实际上并未连接到paypal. (3认同)

sel*_*rai 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);
}
Run Code Online (Sandbox Code Playgroud)

当然,此解决方案仅应用于无法使用keytool例如临时证书的本地测试来安装所需证书的情况.

  • 哇,我会毫不犹豫地称之为"修复".你基本上只是关闭了安全性.是的,数据仍然会被加密,但您不能保证您正在与您希望与之交谈的人交谈.正确的解决方案是获取目标服务器的公钥,并将其导入到建立连接的JVM的信任库中. (46认同)
  • 如果您正在针对开发服务器编写一个非常简单的测试,那么此处显示的代码看起来很有用,但我不会依赖它来进行生产. (3认同)

Shi*_*ari 10

每当我们尝试连接到URL时,

如果其他站点的服务器在https协议上运行并且要求我们通过证书中提供的信息进行通信,那么我们有以下选项:

1)索取证书(下载证书),在trustore中导入此证书.默认的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);
    }
Run Code Online (Sandbox Code Playgroud)

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());
   }
Run Code Online (Sandbox Code Playgroud)

此调用将返回响应代码= 200表示连接成功.

有关更多详细信息和示例示例,您可以参考URL.

  • Google Play 商店将拒绝此操作。他们会发现您在 APK 扫描期间忽略了 X509Certificate。 (2认同)