9

使用 Java URL 类,我可以连接到外部HTTPS服务器(例如我们的生产站点),但是使用本地 URL 我得到以下异常。

"SunCertPathBuilderException: unable to find valid certification path to requested target".

如何获得有效的认证路径?

编辑:我没有使用此 URL 直接创建连接,而是将 URL 传递给itext PDFReader,然后出现连接问题。

4

6 回答 6

13

这是我的解决方案,它结合了该线程中的一些想法,并与来自网络的代码一起使用。我所做的只是调用这个函数,它为 HttpsURLConnection 设置了默认的信任管理器和主机名验证器。这对某些人来说可能是不可取的,因为它会影响所有 HttpsURLConnections,但我只是在编写一个简单的代理,所以它对我有用。

private void setTrustAllCerts() throws Exception
{
    TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType ) { }
            public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType ) { }
        }
    };

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance( "SSL" );
        sc.init( null, trustAllCerts, new java.security.SecureRandom() );
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier( 
            new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            });
    }
    catch ( Exception e ) {
        //We can not recover from this exception.
        e.printStackTrace();
    }
}
于 2009-05-13T19:08:45.573 回答
3

您可能需要设置一个HostnameVerifier. 在连接之前,您需要将其添加到连接对象中

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
  public boolean verify(String hostname, SSLSession session) {
    // check hostname/session
    return true;
  }
});
conn.connect();
// read/write...

如果您需要,肯定有一些实现。您可能还想查看HttpClient项目。

于 2008-12-17T03:00:52.507 回答
3

要查看的另一件事是TrustManager您正在使用。该错误消息表明服务器提供的证书未由受信任的根签名。由于您无法直接控制所创建的 SSL 套接字,因此我认为最好的办法是使用已使用服务器证书链的根 CA 设置的证书来初始化您自己SSLContext的套接字。然后将此上下文设置为默认值TrustManager

这是假设您使用的是 Java 6。Java 5 中的 API 受到更多限制。您可以获得 default SSLSocketFactory,但没有标准的设置方法。

于 2008-12-17T07:06:17.533 回答
0

它抱怨的问题是,当您创建 SSL 连接时,服务器必须向客户端提供有效的证书。您可以在 Java 中编写一个适当的端点(我认为 HTTPServerSocket 会这样做),但它需要一些黑客来设置它。使用可正确处理 SSL 的任何东西(Apache、lighttp 等)设置本地 Web 服务器可能更容易,并使用 openssl 工具创建自签名证书。

更新

这是 Java Almanac 中的一个示例。http://www.exampledepot.com/egs/javax.net.ssl/Server.html

SSL 服务器套接字需要将发送给客户端进行身份验证的证书。证书必须包含在必须明确指定其位置的密钥库中(没有默认值)。在示例之后,我们将描述如何创建和指定要使用的 SSL 服务器套接字的密钥库。

try {
    int port = 443;
    ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
    ServerSocket ssocket = ssocketFactory.createServerSocket(port);

    // Listen for connections
    Socket socket = ssocket.accept();

    // Create streams to securely send and receive data to the client
    InputStream in = socket.getInputStream();
    OutputStream out = socket.getOutputStream();

    // Read from in and write to out...

    // Close the socket
    in.close();
    out.close();
} catch(IOException e) {
}

使用 javax.net.ssl.keyStore 系统属性指定证书的密钥库:

> java -Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456 MyServer
于 2008-12-17T02:56:01.687 回答
0

它还可以帮助您使用“keytool”实用程序将 localhost 服务器正在使用的证书(我假设它是自签名的)添加到 JVM 的密钥库中。这应该有告诉JVM“你可以信任这个证书”的效果。

于 2008-12-17T14:43:39.217 回答
0

我最终运行了一个静态方法(仅在 dev 上),它安装了一个非常信任的 TrustManager(接受所有内容),并且还添加了一个始终返回 true 的 hostnameVerifier(感谢sblundy)。

于 2008-12-17T23:55:59.790 回答