不支持的记录版本SSLv2Hello使用CloseableHttpClient
我正在尝试进行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()); } } }
看来问题在于JDK8客户端无法使用默认提供程序连接到SSL2服务器(SSLv2已过时很长时间)。 您必须强制服务器使用SSL3(或其他更安全的协议),或者必须使用其他提供程序(BouncyCastle?)。 目前,我们在SOAP web服务JDK8客户端和JDK6服务器上遇到类似的问题。
http://en.wikipedia.org/wiki/Transport_Layer_Security#SSL_2.0
http://tools.ietf.org/html/rfc6176
它看起来像你连接到一台服务器,在今天仍然支持SSLv2足够令人难以置信的。
尝试从启用的协议列表中删除SSlv2ClientHello
,但是您可以使用Apache HTTPClient执行此操作。
注意自2004年以来,您并没有使用com.sun.net.ssl.internal.ssl.Provider
东西,并且您需要知道您的TrustManager
和HostnameVerifier
都是根本不安全的。 此外, TrustManager.getAcceptedIssuers()
不允许返回null:请参阅Javadoc。
弄清楚了。 我绊倒鞋带的两个地方是:
需要使用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());
}
}
}
}
}
链接地址: http://www.djcxy.com/p/5979.html
上一篇: Unsupported record version SSLv2Hello using CloseableHttpClient