【问题标题】:HTTPURL connection in java 6/7Java 6/7 中的 HTTPURL 连接
【发布时间】:2017-11-20 08:02:28
【问题描述】:

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

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

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

无法跟踪 url 响应代码,您的 url 可以访问。

这里是堆栈跟踪和javacode

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

感谢是否有人可以帮助解决此问题。谢谢

【问题讨论】:

  • 请在本网站上发布代码,以防止仅链接到外部源。
  • 嗨...它的扩展页面代码。和堆栈跟踪....这就是我包装成链接的原因...如果您无法访问该链接,请告诉我我可以尝试在此处发布整个代码
  • 仅供参考,当 SSL/TLS 握手失败(无论出于何种原因,不仅仅是证书/PKIX 验证)时,没有 HTTP(S) 响应代码(并且根本没有 HTTP(S) 响应)跨度>
  • 我对导入证书做了一些更改,现在我看到错误为 httpURLConnection string: 404 java.net.ProtocolException: Cannot write output after reading input.|认为 url 是可访问的

标签: java ssl httpurlconnection outputstream


【解决方案1】:

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

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

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

代码 sn-p 看起来像这样:

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 实用程序来创建密钥库并加载证书。

【讨论】:

  • 嗨...我需要如何添加密钥库和加载证书...感谢是否可以分享有关如何操作的步骤的详细信息...谢谢!
  • 您好,我尝试利用上面的代码...但是 setSSLSocketFactory 显示错误,因为它未定义 HTTPURLConnection...。您能告知什么是错误的吗?谢谢
  • 您需要首先获得证书 - 最好联系管理服务器端点的人并通过经过验证的渠道请求证书(毕竟您需要信任证书)。您也可以简单地在浏览器中访问端点并提取证书并与服务器端的某个联系人确认证书的指纹。关于如何将证书加载到密钥库中,您需要先创建一个密钥库(这就是 keytool 实用程序的用途)。然后将证书导入密钥库(这两个步骤可以合并)。
  • 试试:keytool -importcert -file&lt;cert_file&gt; -keystore &lt;name_of_truststore&gt; -alias &lt;my_server_cert_domain&gt; 。您还需要将对象转换为HttpsURLConnection 而不是HttpURLConnection 注意'Http'之后的's'。
  • 您好,我已经下载了证书,但是我怎么知道信任库和域的名称,...我在详细信息中找不到它们...。请您简要介绍一下需要采取的措施下载证书后请注意。谢谢
【解决方案2】:

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

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

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

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

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

【讨论】:

  • 嗨...谢谢...您能否分享适当的链接以下载密钥库,安装必须存储在哪里并运行命令导入?
  • -import 选项中的最后 4 个需要参数。对于 java7,另一种以可导入形式获取证书的方法是使用 keytool -printcert -sslserver $host[:$port] -rfc
  • 我对导入证书做了一些更改,现在我看到错误为 httpURLConnection string: 404 java.net.ProtocolException: Cannot write output after reading input.|认为 url 是可以访问的......有什么想法吗?
【解决方案3】:

中间的替代方法是使用您自己的信任库文件(不是JRE/lib/security/cacerts 甚至不是官方替代方案的jssecacerts),而不是编写代码来加载此文件并在SSLSocketFactory 中使用它,您可以拥有默认工厂通过设置系统属性 javax.net.ssl.trustStorejavax.net.ssl.trustStorePassword 来使用您的文件。在许多情况下,这些可以在命令行上设置以运行您的 java 程序,而无需任何代码更改。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2015-11-04
    相关资源
    最近更新 更多