欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

httpclient向HTTPS发送数据建立SSL连接时的异常

程序员文章站 2022-04-25 16:38:16
...
异常信息如下:

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

原因:服务器的证书不被信任。一般是这样造成的。

使用KEYTOOL工具创建证书,然后用TOMCAT启动后,在浏览器打开网站时,会出现证书不被信任的提示。当然,利用HTTPCLIENT向服务端HTTPS发送数据时,HTTPCLIENT也会检测服务端的证书是否被信任,不被信任就抛出上面的异常。

解决办法有两种,一种是使证书被客户端信任。另一种是使用HTTPCLIENT发送数据时不检测服务器证书是否可信。

第一种办法,使证书被信任。

找正规CA签发证书,或者自己签发证书(只能那一台客户机上可信)。找正规CA签发证书就不说了,自己签发证书呢,见我的其他文章。

我发现,自己签名的证书弄好之后,从客户端打开服务端地址时,不再提示上面的错误,但是还是不能发送数据。原因是什么呢?因为那台证书在客户端操作系统上可信,但是在JAVA的KEYSTORE里不可信,要把服务端的证书导入KEYSTORE库中

导入办法:

打开命令行窗口,并到<java-home>\lib\security\ 目录下,运行下面的命令:

keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer

最后一个是服务端导出的证书,其他可以默认。

要注意的是,如果客户端电脑上装有许多个JAVA版本,要确定你导入的证书的JAVA版本是你TOMCAT使用的那个,一般TOMCAT使用的是环境变量指向的那个JAVA版本。

如果是在ECLIPSE中建立的TOMCAT服务器,新建时会要你选择默认JRE还是指向的JAVA,这里一定要选指向刚才导入的那个JAVA的路径,不然,你导入的证书库也没效果。

第二种办法,使用HTTPCLIENT时不检测服务器证书是否可信

扩展HttpClient 类实现自动接受证书

因为这种方法自动接收所有证书,因此存在一定的安全问题,所以在使用这种方法前请仔细考虑您的系统的安全需求。具体的步骤如下:

•提供一个自定义的socket factory (test.MySecureProtocolSocketFactory )。这个自定义的类必须实现接口org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory ,在实现接口的类中调用自定义的X509TrustManager(test.MyX509TrustManager) ,这两个类可以在随本文带的附件中得到

•创建一个org.apache.commons.httpclient.protocol.Protocol 的实例,指定协议名称和默认的端口号

Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);

•注册刚才创建的https 协议对象

Protocol.registerProtocol("https ", myhttps);

•然后按照普通编程 方式打开https 的目标地址,代码如下:

MySecureProtocolSocketFactory.java

import java.io.IOException;  
    import java.net.InetAddress;  
    import java.net.InetSocketAddress;  
    import java.net.Socket;  
    import java.net.SocketAddress;  
    import java.net.UnknownHostException;  
    import java.security.KeyManagementException;  
    import java.security.NoSuchAlgorithmException;  
    import java.security.cert.CertificateException;  
    import java.security.cert.X509Certificate;  
      
    import javax.net.SocketFactory;  
    import javax.net.ssl.SSLContext;  
    import javax.net.ssl.TrustManager;  
    import javax.net.ssl.X509TrustManager;  
      
    import org.apache.commons.httpclient.ConnectTimeoutException;  
    import org.apache.commons.httpclient.params.HttpConnectionParams;  
    import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;  
      
    public class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory {  
        private SSLContext sslcontext = null;  
          
        private SSLContext createSSLContext() {  
            SSLContext sslcontext=null;  
            try {  
                sslcontext = SSLContext.getInstance("SSL");  
                sslcontext.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());  
            } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
            } catch (KeyManagementException e) {  
                e.printStackTrace();  
            }  
            return sslcontext;  
        }  
          
        private SSLContext getSSLContext() {  
            if (this.sslcontext == null) {  
                this.sslcontext = createSSLContext();  
            }  
            return this.sslcontext;  
        }  
          
        public Socket createSocket(Socket socket, String host, int port, boolean autoClose)  
                throws IOException, UnknownHostException {  
            return getSSLContext().getSocketFactory().createSocket(  
                    socket,  
                    host,  
                    port,  
                    autoClose  
                );  
        }  
      
        public Socket createSocket(String host, int port) throws IOException,  
                UnknownHostException {  
            return getSSLContext().getSocketFactory().createSocket(  
                    host,  
                    port  
                );  
        }  
          
          
        public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)  
                throws IOException, UnknownHostException {  
            return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);  
        }  
      
        public Socket createSocket(String host, int port, InetAddress localAddress,  
                int localPort, HttpConnectionParams params) throws IOException,  
                UnknownHostException, ConnectTimeoutException {  
            if (params == null) {  
                throw new IllegalArgumentException("Parameters may not be null");  
            }  
            int timeout = params.getConnectionTimeout();  
            SocketFactory socketfactory = getSSLContext().getSocketFactory();  
            if (timeout == 0) {  
                return socketfactory.createSocket(host, port, localAddress, localPort);  
            } else {  
                Socket socket = socketfactory.createSocket();  
                SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);  
                SocketAddress remoteaddr = new InetSocketAddress(host, port);  
                socket.bind(localaddr);  
                socket.connect(remoteaddr, timeout);  
                return socket;  
            }  
        }  
          
        //自定义私有类  
        private static class TrustAnyTrustManager implements X509TrustManager {  
             
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
            }  
         
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
            }  
         
            public X509Certificate[] getAcceptedIssuers() {  
                return new X509Certificate[]{};  
            }  
        }  
          
      
    }