如何在java中使用本地HTTPS URL?

时间:2008-12-17 02:48:23

标签: java https certificate

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

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

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

编辑:我没有使用此网址直接创建连接,我将网址传递给itext PDFReader,然后发生连接问题。

6 个答案:

答案 0 :(得分:13)

这是我的解决方案,它结合了这个主题中的一些想法,并与来自网络的代码一起调整。 所有我都调用此函数,它为HttpsURLConnection设置默认的Trust Manager和HostName Verifier。这对某些人来说可能是不受欢迎的,因为它会影响所有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();
    }
}

答案 1 :(得分: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项目。

答案 2 :(得分:3)

要看的另一件事是你正在使用的TrustManager。该错误消息表明服务器提供的证书未由受信任的根签名。由于您无法直接控制所创建的SSL套接字,因此我认为您最好的选择是initialize您自己的SSLContext TrustManagersetup with the root CA服务器的证书链。然后将此上下文设置为default

这假设您使用的是Java 6.在Java 5中,API更受限制。您可以获得默认的SSLSocketFactory,但没有标准的方法来设置它。

答案 3 :(得分: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

答案 4 :(得分:0)

它还可以帮助您将本地主机服务器正在使用的证书(我假设它是自签名的)添加到JVM的keystoreusing the "keytool" utility。这应该会告诉JVM“你可以信任这个证书”。

答案 5 :(得分:0)

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