115

我连接了 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
4

6 回答 6

166

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

现在您已将证书保存在文件中,您需要将其添加到 JVM 的信任库中。$JAVA_HOME/jre/lib/security/对于 JRE 或JDK,有$JAVA_HOME/lib/security一个名为 的文件cacerts,它随 Java 一起提供,包含著名的认证机构的公共证书。要导入新证书,请以有权写入 cacerts 的用户身份运行 keytool:

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

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

于 2011-07-19T04:08:44.757 回答
19

现在我以这种方式解决了这个问题,

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临时证书进行本地测试来安装所需证书的情况下使用。

于 2011-07-19T03:52:30.880 回答
11

每当我们尝试连接到 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);
    }

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

于 2014-03-20T05:54:55.820 回答
0

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

  1. 结合 SSL

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

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

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

  2. 忽略 SSL

    对于这个 #2,请访问我在另一个 stackoverflow 网站上的另一个答案: 如何使用 Java 进行 SSL 验证忽略 SSL 证书错误

于 2017-03-16T02:04:59.670 回答
-1

我相信您正在尝试使用 SSL 连接到某个东西,但是某些东西正在提供一个未经根证书颁发机构(例如 verisign)验证的证书。本质上,默认情况下,只有在尝试连接的人知道的情况下才能建立安全连接交易对手的密钥或其他一些验证者(例如威瑞信)可以介入并说所提供的公钥确实是正确的。

如果您明白我的意思,所有操作系统都信任少数认证机构和较小的证书颁发者需要由一个大型认证机构进行认证,该认证机构会制作一系列认证机构......

无论如何,回到正题..我在编写一个 java applet 和一个 java 服务器时遇到了一个类似的问题(希望有一天我会写一篇完整的博文,讲述我是如何让所有的安全性工作的 :))

本质上,我必须做的是从服务器中提取公钥并将其存储在我的小程序内的密钥库中,当我连接到服务器时,我使用这个密钥库来创建一个信任工厂和那个信任工厂来创建 ssl联系。还有一些替代过程,例如将密钥添加到 JVM 的受信任主机并在启动时修改默认信任存储。

大约两个月前我这样做了,现在我没有源代码..使用谷歌,你应该能够解决这个问题。如果你不能给我发消息,我可以为你提供项目的相关源代码。不知道这是否解决了你的问题,因为你没有提供导致这些异常的代码。此外,我正在使用小程序,我认为我不明白为什么它不能在 Serverlets 上工作......

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

于 2011-07-14T17:53:36.227 回答
-7

现在我以这种方式解决了这个问题,

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);
}
于 2015-11-30T01:26:28.873 回答