首页 文章

使用CloseableHttpClient的不受支持的记录版本SSLv2Hello

提问于
浏览
3

我正在尝试进行https调用并收到以下错误:不支持的记录版本SSLv2Hello

任何人都可以说明我做错了什么?谢谢你的帮助 .

这是StackTrace:

debug:
    Unsupported record version SSLv2Hello
    javax.net.ssl.SSLException: Unsupported record version SSLv2Hello
    at sun.security.ssl.InputRecord.readV3Record(Unknown Source)
    at sun.security.ssl.InputRecord.read(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
    at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:123)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:318)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at httpcomponents.httpsTest.main(httpsTest.java:135)

这是工作示例:

import com.sun.net.ssl.internal.ssl.Provider;
    import java.io.IOException;
    import java.security.KeyManagementException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.text.MessageFormat;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.TimeUnit;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLException;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    import org.apache.http.Header;
    import org.apache.http.HttpHeaders;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpHead;
    import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLContexts;
    import org.apache.http.conn.ssl.X509HostnameVerifier;
    import org.apache.http.entity.ContentType;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.apache.http.protocol.BasicHttpContext;
    import org.apache.http.protocol.HttpContext; 
    String audioURL = "https://mydata.com/webreports/audio.jsp?callID=338786512&authentication=98695279578B04166629C0";
    RequestConfig requestConfig = null;
        requestConfig = RequestConfig
            .custom()
            .setConnectTimeout(5000)
            .setConnectionRequestTimeout(5000)
            .setSocketTimeout(5000)
            .build();
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = null;
    poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
    poolingHttpClientConnectionManager.setMaxTotal(5);
    CloseableHttpClient closeableHttpClient = null;
    HttpHead httpHead = new HttpHead(audioURL);
    try {
        Provider sslProvider = new Provider();
        if (Security.getProvider(sslProvider.getName()) == null) {
            Security.addProvider(sslProvider);
        }
        TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                }
                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                }
            }
        };
        SSLContext sslContext = SSLContexts
                .custom()
                .useSSL()
                .build();
        sslContext.init(null, trustAllCerts, new SecureRandom());
        LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
        X509HostnameVerifier x509HostnameVerifier = new X509HostnameVerifier() {
            @Override
            public void verify(String host, SSLSocket ssl) throws IOException {
                //do nothing
            }
            @Override
            public void verify(String host, X509Certificate cert) throws SSLException {
                //do nothing                                                            //do nothing
            }
            @Override
            public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
                //do nothing
            }
            @Override
            public boolean verify(String string, SSLSession ssls) {
                return true;
            }
        };
        closeableHttpClient = HttpClientBuilder
                .create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(poolingHttpClientConnectionManager)
                .setSslcontext(sslContext)
                .setHostnameVerifier(x509HostnameVerifier)
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .build();
    } catch (NoSuchAlgorithmException noSuchAlgorithmException) {
        System.out.println(noSuchAlgorithmException.getMessage());
    } catch (KeyManagementException keyManagementException) {
        System.out.println(keyManagementException.getMessage());
    }
    HttpContext httpContext = new BasicHttpContext();
    CloseableHttpResponse closeableHttpResponse = null;
    try {
        if (closeableHttpClient != null) {
            closeableHttpResponse = closeableHttpClient.execute(httpHead, httpContext);
            if (closeableHttpResponse != null) {
                int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
                System.out.println(String.valueOf(statusCode));
            }
        }
    } catch (IOException iOException) {
        System.out.println(iOException.getMessage());
    } finally {
        if (closeableHttpResponse != null) {
            try {
                closeableHttpResponse.close();
            } catch (IOException iOException) {
                System.out.println(iOException.getMessage());
            }
        }
        if (closeableHttpClient != null) {
            try {
                closeableHttpClient.close();
            } catch (IOException iOException) {
                System.out.println(iOException.getMessage());
            }
        }
    }

3 回答

  • 1

    弄清楚了 . 我绊倒鞋带的两个地方是:

    需要使用PoolingHttpClientConnectionManager注册https

    将TLSv1设置为SSLConnectionSocketFactory中唯一受支持的协议

    package httpcomponents;
    
    import java.io.IOException;
    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLException;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocket;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpHead;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
    import org.apache.http.conn.socket.PlainConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.conn.ssl.SSLContexts;
    import org.apache.http.conn.ssl.TrustStrategy;
    import org.apache.http.conn.ssl.X509HostnameVerifier;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    
    /**
     *
     * @author mark.jones
     */
    public class HttpTest3 {
    
        public static void main(String[] args) {
            CloseableHttpClient closeableHttpClient = null;
            CloseableHttpResponse closeableHttpResponse = null;
            try {
                HttpHead httpHead = null;
                TrustStrategy trustStrategy = null;
                SSLContext sslContext = null;
                X509HostnameVerifier x509HostnameVerifier = null;
                LayeredConnectionSocketFactory sslConnectionSocketFactory = null;
                Registry<ConnectionSocketFactory> registry = null;
                PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = null;
                RequestConfig requestConfig = null;
                String audioURL = "https://ancientserver.com/webreports/audio.jsp?callID=338786512&authentication=98695279578B04166629C0AC0ABB49F0";
    
                httpHead = new HttpHead(audioURL);
    
                trustStrategy = new TrustStrategy() {
                    @Override
                    public boolean isTrusted(X509Certificate[] xcs, String authType) throws CertificateException {
                        return true;
                    }
                };
    
                sslContext = SSLContexts
                        .custom()
                        .useSSL()
                        .loadTrustMaterial(null, trustStrategy)
                        .setSecureRandom(new SecureRandom())
                        .build();
    
                x509HostnameVerifier = new X509HostnameVerifier() {
                    @Override
                    public void verify(String host, SSLSocket ssl) throws IOException {
                        //do nothing
                    }
    
                    @Override
                    public void verify(String host, X509Certificate cert) throws SSLException {
                        //do nothing                                                            //do nothing
                    }
    
                    @Override
                    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
                        //do nothing
                    }
    
                    @Override
                    public boolean verify(String string, SSLSession ssls) {
                        return true;
                    }
                };
    
                //either one works
                //LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, x509HostnameVerifier);
    
                registry = RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
                        .register("https", sslConnectionSocketFactory)
                        .build();
    
                poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);
    
                requestConfig = RequestConfig
                        .custom()
                        .setConnectTimeout(5000)            //5 seconds
                        .setConnectionRequestTimeout(5000)
                        .setSocketTimeout(5000)
                        .build();
    
                closeableHttpClient = HttpClientBuilder
                        .create()
                        .setDefaultRequestConfig(requestConfig)
                        .setSslcontext(sslContext)
                        .setHostnameVerifier(x509HostnameVerifier)
                        .setSSLSocketFactory(sslConnectionSocketFactory)
                        .setConnectionManager(poolingHttpClientConnectionManager)
                        .build();
    
                if (closeableHttpClient != null) {
                    closeableHttpResponse = closeableHttpClient.execute(httpHead);
                    if (closeableHttpResponse != null) {
                        int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
                        System.out.println(String.valueOf(statusCode));
                        System.out.println(closeableHttpResponse.getFirstHeader("Content-Type"));
                    }
                }
            } catch (NoSuchAlgorithmException noSuchAlgorithmException) {
                System.out.println(noSuchAlgorithmException.getMessage());
            } catch (KeyStoreException keyStoreException) {
                System.out.println(keyStoreException.getMessage());
            } catch (KeyManagementException keyManagementException) {
                System.out.println(keyManagementException.getMessage());
            } catch (IOException iOException) {
                System.out.println(iOException.getMessage());
            } finally {
                if (closeableHttpResponse != null) {
                    try {
                        closeableHttpResponse.close();
                    } catch (IOException iOException) {
                        System.out.println(iOException.getMessage());
                    }
                }
                if (closeableHttpClient != null) {
                    try {
                        closeableHttpClient.close();
                    } catch (IOException iOException) {
                        System.out.println(iOException.getMessage());
                    }
                }
            }
        }
    }
    
  • 1

    看起来你正在连接到服务器,在这个时代,它仍然支持SSLv2 .

    尝试从启用的协议列表中删除 SSlv2ClientHello ,但是您可以使用Apache HTTPClient执行此操作 .

    NB你自2004年以来就没有需要 com.sun.net.ssl.internal.ssl.Provider 那些东西了,你需要知道你的 TrustManagerHostnameVerifier 都是根本不安全的 . 另外 TrustManager.getAcceptedIssuers() 不允许返回null:请参阅Javadoc .

  • 5

    似乎问题是JDK8客户端无法使用默认Provider连接到SSL2服务器(SSLv2已被弃用很长时间) . 您必须强制服务器使用SSL3(或其他更安全的协议),或者您必须使用其他提供程序(BouncyCastle?) . 目前我们在SOAP webservice JDK8客户端和JDK6服务器上遇到了类似的问题 .

    http://en.wikipedia.org/wiki/Transport_Layer_Security#SSL_2.0

    http://tools.ietf.org/html/rfc6176

相关问题