如何在HttpClient上更改支持的TLS版本?
我在做:
SSLContext sslContext = SSLContext.getInstance("TLSv1.1");
sslContext.init(
keymanagers.toArray(new KeyManager[keymanagers.size()]),
null,
null);
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, new String[]{"TLSv1.1"}, null, null);
Scheme scheme = new Scheme("https", 443, socketFactory);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(scheme);
BasicClientConnectionManager cm = new BasicClientConnectionManager(schemeRegistry);
httpClient = new DefaultHttpClient(cm);
但是当我检查创建的套接字时,它仍然说支持的协议是TLSv1.0,TLSv1.1和TLSv1.2。
实际上我只是希望它停止使用TLSv1.2,对于这个特定的HttpClient。
答案 0 :(得分:33)
解决方案是:
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.build();
SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1", "TLSv1.1"},
null,
BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom()
.setSSLSocketFactory(f)
.build();
这需要org.apache.httpcomponents.httpclient 4.3.x尽管。
答案 1 :(得分:14)
这就是我如何使用httpClient 4.5(根据Olive Tree请求):
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, 443),
new UsernamePasswordCredentials(this.user, this.password));
SSLContext sslContext = SSLContexts.createDefault();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1", "TLSv1.1"},
null,
new NoopHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setSSLSocketFactory(sslsf)
.build();
return httpclient;
答案 2 :(得分:8)
HttpClient-4.5,使用TLSv1.2,你必须这样编码:
//Set the https use TLSv1.2
private static Registry<ConnectionSocketFactory> getRegistry() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext sslContext = SSLContexts.custom().build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
return RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
}
public static void main(String... args) {
try {
//Set the https use TLSv1.2
PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(getRegistry());
clientConnectionManager.setMaxTotal(100);
clientConnectionManager.setDefaultMaxPerRoute(20);
HttpClient client = HttpClients.custom().setConnectionManager(clientConnectionManager).build();
//Then you can do : client.execute(HttpGet or HttpPost);
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
答案 3 :(得分:5)
对于使用TLSv1.2的HttpClient-4.1,代码将是这样的:
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, new SecureRandom());
SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
HttpClient client = new DefaultHttpClient(cm);
// Use client to make the connection and get the results.
答案 4 :(得分:4)
使用HttpClient 4.5.x中的HttpClientBuilder
和自定义HttpClientConnectionManager
,默认值为HttpClientBuilder
:
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(SSLContexts.createDefault(),
new String[] { "TLSv1.2" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory> create()
.register("http",
PlainConnectionSocketFactory.getSocketFactory())
.register("https",
sslConnectionSocketFactory)
.build());
// Customize the connection pool
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.build()
没有自定义HttpClientConnectionManager
:
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(SSLContexts.createDefault(),
new String[] { "TLSv1.2" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build()
答案 5 :(得分:2)
如果您使用的是httpclient 4.2,那么您需要编写一些额外的代码。我希望能够自定义“支持TLS的协议”(例如TLSv1.1
,TLSv1
和TLSv1.2
}以及cipher suites。
public class CustomizedSSLSocketFactory
extends SSLSocketFactory
{
private String[] _tlsProtocols;
private String[] _tlsCipherSuites;
public CustomizedSSLSocketFactory(SSLContext sslContext,
X509HostnameVerifier hostnameVerifier,
String[] tlsProtocols,
String[] cipherSuites)
{
super(sslContext, hostnameVerifier);
if(null != tlsProtocols)
_tlsProtocols = tlsProtocols;
if(null != cipherSuites)
_tlsCipherSuites = cipherSuites;
}
@Override
protected void prepareSocket(SSLSocket socket)
{
// Enforce client-specified protocols or cipher suites
if(null != _tlsProtocols)
socket.setEnabledProtocols(_tlsProtocols);
if(null != _tlsCipherSuites)
socket.setEnabledCipherSuites(_tlsCipherSuites);
}
}
然后:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, getTrustManagers(), new SecureRandom());
// NOTE: not javax.net.SSLSocketFactory
SSLSocketFactory sf = new CustomizedSSLSocketFactory(sslContext,
null,
[TLS protocols],
[TLS cipher suites]);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);
ConnectionManager cm = new BasicClientConnectionManager(schemeRegistry);
HttpClient client = new DefaultHttpClient(cmgr);
...
您可以使用略少的代码执行此操作,但我主要通过自定义组件进行复制/粘贴,以便按上述方式构建对象。
答案 6 :(得分:2)
如果您的代码中有javax.net.ssl.SSLSocket类引用,则可以通过调用SSLSocket.setEnabledProtocols()来设置启用的TLS协议:
import javax.net.ssl.*;
import java.net.*;
...
Socket socket = SSLSocketFactory.getDefault().createSocket();
...
if (socket instanceof SSLSocket) {
// "TLSv1.0" gives IllegalArgumentException in Java 8
String[] protos = {"TLSv1.2", "TLSv1.1"}
((SSLSocket)socket).setEnabledProtocols(protos);
}
答案 7 :(得分:0)
您可以在服务器上指定以下属性-Dhttps.protocols = TLSv1.1,TLSv1.2,它配置JVM以指定在来自客户端的所有https连接期间应使用哪个TLS协议版本。
答案 8 :(得分:0)
使用-Dhttps.protocols = TLSv1.2 JVM参数对我不起作用。起作用的是以下代码
RequestConfig.Builder requestBuilder = RequestConfig.custom();
//other configuration, for example
requestBuilder = requestBuilder.setConnectTimeout(1000);
SSLContext sslContext = SSLContextBuilder.create().useProtocol("TLSv1.2").build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestBuilder.build());
builder.setProxy(new HttpHost("your.proxy.com", 3333)); //if you have proxy
builder.setSSLContext(sslContext);
HttpClient client = builder.build();
使用以下JVM参数进行验证
-Djavax.net.debug=all
答案 9 :(得分:0)
由于这只是隐藏在注释中,因此很难找到解决方案:
您可以使用java -Dhttps.protocols=TLSv1,TLSv1.1
,但是您还需要使用useSystemProperties()
client = HttpClientBuilder.create().useSystemProperties();
我们现在在系统中使用此设置,因为这使我们只能为某些代码用法设置此设置。
在我们的情况下,我们仍然在运行Java 7,并且一个API端点不允许使用TLSv1,
因此我们使用java -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2
启用当前的TLS版本。
感谢@jebeaudet指出了这个方向。