>  기사  >  백엔드 개발  >  httpclient가 SSL 연결을 설정하기 위해 데이터를 HTTPS로 보낼 때 예외

httpclient가 SSL 연결을 설정하기 위해 데이터를 HTTPS로 보낼 때 예외

巴扎黑
巴扎黑원래의
2016-12-20 15:08:391776검색

예외 정보는 다음과 같습니다.

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX 경로 구축 실패: sun.security.provider.certpath.SunCertPathBuilderException: 찾을 수 없습니다. 요청한 대상에 대한 유효한 인증 경로

원인: 서버의 인증서를 신뢰할 수 없습니다. 이는 일반적으로 발생합니다.

KEYTOOL 도구를 사용하여 인증서를 만든 다음 TOMCAT으로 시작하면 브라우저가 웹 사이트를 열 때 인증서를 신뢰할 수 없다는 메시지가 나타납니다. 물론 HTTPCLIENT를 사용하여 HTTPS 서버에 데이터를 보내는 경우 HTTPCLIENT는 서버의 인증서를 신뢰할 수 있는지 여부도 감지합니다. 신뢰할 수 없는 경우 위의 예외가 발생합니다.

두 가지 해결책이 있습니다. 하나는 클라이언트가 인증서를 신뢰하도록 만드는 것입니다. 다른 하나는 HTTPCLIENT를 사용하여 서버 인증서를 신뢰할 수 있는지 확인하지 않고 데이터를 보내는 것입니다.

첫 번째 방법은 인증서를 신뢰할 수 있게 만드는 것입니다.

인증서를 발급할 공식 CA를 찾거나 직접 인증서를 발급하세요(해당 클라이언트에서만 신뢰할 수 있음). 인증서를 발급할 공식 CA를 찾는 방법에 대해서는 언급하지 않겠습니다. 인증서를 직접 발급하는 방법은 내 다른 기사를 참조하세요.

직접 서명한 인증서를 완성한 후 클라이언트에서 서버 주소를 열었을 때 위의 오류가 더 이상 표시되지 않지만 여전히 데이터를 보낼 수 없다는 것을 발견했습니다. 이유는 무엇입니까? 클라이언트 운영 체제에서는 인증서를 신뢰하지만 JAVA의 KEYSTORE에서는 신뢰하지 않기 때문에 서버의 인증서를 KEYSTORE 라이브러리

가져오기 방법:

으로 가져와야 합니다. 명령줄 창을 열고 63b3ee7e72479f6360d4c7e4b3af780alibsecurity 디렉토리로 이동하여 다음 명령을 실행합니다.

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

마지막은 서버에서 내보낸 인증서이고 나머지는 기본값으로 설정할 수 있습니다.

클라이언트 컴퓨터에 설치된 JAVA 버전이 많은 경우 가져오는 인증서의 JAVA 버전이 TOMCAT에서 사용되는 버전인지 확인하세요. TOMCAT은 변수가 가리키는 JAVA 버전 환경을 사용합니다.

ECLIPSE에서 생성된 TOMCAT 서버인 경우 새 서버를 생성할 때 기본 JRE 또는 지정된 JAVA를 선택하라는 메시지가 표시됩니다. 그렇지 않으면 방금 가져온 JAVA를 가리키는 경로를 선택해야 합니다. 가져온 인증서 라이브러리도 영향을 받지 않습니다.

두 번째 방법은 HTTPCLIENT를 사용할 때 서버 인증서를 신뢰할 수 있는지 확인하지 않는 것입니다.

인증서를 자동으로 수락하도록 HttpClient 클래스를 확장합니다

이 방법은 모든 인증서를 자동으로 받기 때문에 특정 보안 문제가 있으므로 이 방법을 사용하기 전에 시스템의 보안 요구 사항을 신중하게 고려하십시오. 구체적인 단계는 다음과 같습니다.

• 사용자 정의 소켓 팩토리(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[]{};  
            }  
        }  
          
      
    }


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.