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


101

我连接了VPN,以设置广告资源API来获取产品列表,并且效果很好。一旦我从Web服务获得结果并绑定到UI。当我遇到付款错误时,我也将PayPal与我的make Express结帐应用程序集成在一起。我将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

1
我想知道的是,在那种情况下是哪个确切目标……您遇到了一个例外,但是您没有获得有关目标的信息,这可能与您的预期有所不同。有证书,但我仍然遇到这种例外情况
ante.sabo 2012年

Answers:


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证书。我做了您的步骤,并且证书也添加到了适当的位置。然后我运行的应用程序说同样的错误?
selladurai 2011年

实际上,它在没有问题的浏览器中运行良好,并且当时我用VPN连接到库存清单,我用PayPal付款,它说是SSL错误,但是我使用离线数据或热编码数据意味着它可以工作。
selladurai 2011年

4
@selladurai:您不需要为贝宝导入证书。除非您的cacerts文件已损坏或被修改,否则它应包含所有受信任的根证书,并且paypal的证书应能够追溯到其中之一。您可以尝试获取一份您知道是不错的证书的副本,然后尝试使用该证书。如果问题仍然存在,则您可能实际上未连接到Paypal。
瑞安·斯图尔特

@RyanStewart我是否需要以某种方式将其导入到glassfish?因为我确实将.cer文件添加到了我的Java主目录中的cacert中,但是glassfish似乎没有使用它,所以我仍然遇到错误。
Ced 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
请参阅我的答案以寻求适当的解决方案
Ryan Stewart

例子是什么?我的答案应该包含您需要的所有步骤。
瑞安·斯图尔特


3
如果您要针对开发服务器编写非常简单的测试,则此处显示的代码很有帮助,尽管我不会将其用于生产。
杰森D

12

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

如果另一个站点上的服务器运行在https协议上并且要求我们通过证书中提供的信息进行通信,则可以使用以下选项:

1)索取证书(下载证书),并在trustore中导入此证书。可以在\ Java \ jdk1.6.0_29 \ jre \ lib \ security \ cacerts中找到默认的trustore Java使用,然后接受重新连接到URL的连接。

2)在正常的业务情况下,我们可能会连接到组织中的内部URL,我们知道它们是正确的。在这种情况下,您相信它是正确的URL。在上述情况下,可以使用不强制存储证书以连接到特定URL的代码。

对于第二点,我们必须执行以下步骤:

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


1
Google Play商店将拒绝此操作。他们会看到您在APK扫描过程中忽略了X509Certificate。
奥利弗·迪克森

0

我相信您正在尝试使用SSL连接到某物,但某物正在提供未经root证书颁发机构(例如verisign)验证的证书。本质上,默认情况下,仅当试图连接的人知道时,才能建立安全连接交易对手的密钥或诸如verisign之类的其他厂商可能会介入,并说提供的公共密钥确实是正确的。

ALL OS信任少数几个证书颁发机构,并且较小的证书颁发者需要由大型认证机构之一进行认证,如果您明白我的意思,那么该认证机构将组成一系列认证机构。

无论如何都回到了要点。.在编写Java小程序和Java服务器时遇到了类似的问题(希望有一天,我将写一篇完整的博客文章,介绍如何使所有安全性发挥作用:))

本质上,我要做的是从服务器中提取公钥并将其存储在我的applet内的密钥库中,当我连接到服务器时,我使用此密钥库创建了一个信任工厂,而那个信任工厂创建了ssl。连接。还有一些备用过程,例如将密钥添加到JVM的可信主机,并在启动时修改默认的信任库。

我大约两个月前做了这个,现在还没有源代码。使用google,您应该可以解决此问题。如果您不能给我回信,并且我可以为您提供该项目的相关事件源代码,则不知道这是否可以解决您的问题,因为您没有提供导致这些异常的代码。此外,我在用小程序工作,以为我看不到为什么它不能在Serverlets上工作...

PS我不能在周末之前获得源代码,因为我的办公室已禁用外部SSH :(


1
PS我在网上找到了此Java代码来提取和存储服务器的公钥,因此请继续使用Google搜寻或等到周日
Osama Javed

0

SSLHandshakeException可以通过2种方式解决。

  1. 整合SSL

    • 获取SSL(通过询问源系统管理员,也可以通过openssl命令下载,或者任何浏览器都下载证书)

    • 将证书添加到位于JRE / lib / security的信任库(证书)中

    • 在vm参数中将信任库位置提供为“ -Djavax.net.ssl.trustStore =“

  2. 忽略SSL

    对于此#2,请在另一个stackoverflow网站上访问我的其他答案: 如何进行SSL验证忽略Java的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连接不安全。不要这样
罗恩侯爵(Marques of Lorne)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.