java 6/7中的HTTPURL连接

时间:2017-06-17 18:20:17

标签: java ssl httpurlconnection outputstream

我有一个带HTTPURL连接的java代码,它一直在说错误,如下所示,它表示第47行的错误。

  

javax.net.ssl.SSLHandshakeException:   sun.security.validator.ValidatorException:PKIX路径构建失败:   sun.security.provider.certpath.SunCertPathBuilderException:无法   找到所请求目标的有效证书路径|

它还在第47行显示错误:OutputStream output = httpURLConnection.getOutputStream();

无法跟踪网址响应代码,您可以自动访问该网址。

这里是堆栈跟踪和javacode

https://gist.github.com/theakathir/c9138e3ea7470b698ec06a7db7dcdeab

感谢有人可以协助解决这个问题。感谢

3 个答案:

答案 0 :(得分:2)

服务器的域证书通常由中间证书颁发机构签名,中间证书颁发机构又由根证书颁发机构签名。所有常见的客户端(浏览器 - chrome,mozilla,internet-explorer,safari,opera和java-vm)都有自己的信任存储,并且在安装过程中已经捆绑了证书颁发机构。

例外意味着您指向的服务器的服务器证书尚未由jvm信任的证书颁发机构签名。

在这种情况下,您通常会构建自己的信任管理器,而不是修改jvm的默认信任库(位于$JAVA_HOME\jre\lib\security\cacerts)。

代码段看起来像这样:

package com.example.so.tls;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;


/**
 * <p> https://stackoverflow.com/q/44607949/2862341 </p>
 * @author ravindra
 */
public class TestCustomTruststore {

    public static void main(String[] args) {

        String pathToTruststore = "/path/to/customTruststore.jks"; // truststore has the server certificate loaded
        try {
            File file = new File(pathToTruststore);
            KeyStore trustStore = KeyStore.getInstance("jks");
            trustStore.load(new FileInputStream(file), null);
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
            trustManagerFactory.init(trustStore);

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            String urlStr = "https://example.com";
            URL url = new URL(urlStr);
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
            httpsURLConnection.setSSLSocketFactory(sslSocketFactory);

            httpsURLConnection.getInputStream();

        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }


    }

}

PS:您需要使用$JAVA_HOME\bin\keytool实用程序来创建密钥库并加载证书。

答案 1 :(得分:1)

您需要将证书添加到位于%JAVA_HOME%\ lib \ security \ cacerts的已使用JVM的密钥库文件中。

首先,您可以通过运行以下命令来检查您的证书是否已经存在于密钥库中:keytool -list -keystore“%JAVA_HOME%/ jre / lib / security / cacerts”(您无需提供密码)

如果您的证书丢失,可以通过浏览器下载并使用以下命令将其添加到密钥库来获取证书:

keytool -import -noprompt -trustcacerts -alias -file -keystore -storepass

安装导入后,您可以再次运行第一个命令,检查您的证书是否已添加。

答案 2 :(得分:0)

中间替代方案是使用您自己的信任库文件(不是JRE/lib/security/cacerts甚至是jssecacerts这是官方备选方案)但不是编写代码来加载此文件并在{{1}中使用它您可以通过设置系统属性SSLSocketFactoryjavax.net.ssl.trustStore让默认工厂使用您的文件。在许多情况下,这些可以在命令行上设置,以运行您的Java程序,而不需要任何代码更改。

请注意,当今Internet上几乎所有SSL / TLS证书都不是由根CA(位于各种浏览器,客户端和JVM信任库中)直接颁发,而是使用也称为“链”证书的中间CA证书因为它用于从服务器/叶子证书链接到根证书。偶尔会有两个链证书,原则上可以更多。 验证错误可能不是由缺少root的JVM引起的,而是由服务器未能发送链证书引起的;使用浏览器访问时可能不会注意到此错误,因为浏览器有时会使用其他方式获取链证书。在这种情况下,要么手动检查证书链 - 对于java7,您可以使用javax.net.ssl.trustStorePassword和/或如果您使用openssl使用keytool -printcert -sslserver $host[:$port],然后在每个PEM块上使用openssl s_client -connect $host:$port -showcerts 在该输出中 - 或使用像https://www.ssllabs.com/ssltest/

这样的自动测试程序