How to set TLS version on apache HttpClient

匿名 (未验证) 提交于 2019-12-03 01:10:02

问题:

How can I change the supported TLS versions on my HttpClient?

I'm doing:

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); 

But when I check the created socket, it still says the supported protocols are TLSv1.0, TLSv1.1 and TLSv1.2.

In reality I just want it to stop using TLSv1.2, for this specific HttpClient.

回答1:

The solution is:

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(); 

This requires org.apache.httpcomponents.httpclient 4.3.x though.



回答2:

This is how I got it working on httpClient 4.5 (as per Olive Tree request):

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; 


回答3:

HttpClient-4.5,Use TLSv1.2 ,You must code like this:

 //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();     } } 


回答4:

For HttpClient-4.1 using TLSv1.2, code would go something like this:

        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. 


回答5:

Using the HttpClientBuilder in HttpClient 4.5.x with a custom HttpClientConnectionManager with the defaults of 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() 

Without a custom HttpClientConnectionManager :

SSLConnectionSocketFactory sslConnectionSocketFactory =      new SSLConnectionSocketFactory(SSLContexts.createDefault(),                                              new String[] { "TLSv1.2" },                                                                                null,             SSLConnectionSocketFactory.getDefaultHostnameVerifier());  CloseableHttpClient httpClient = HttpClientBuilder.create()                                                   .setSSLSocketFactory(sslConnectionSocketFactory)                                                   .build() 


回答6:

If you are using httpclient 4.2, then you need to write a small bit of extra code. I wanted to be able to customize both the "TLS enabled protocols" (e.g. TLSv1.1 specifically, and neither TLSv1 nor TLSv1.2) as well as the 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);     } } 

Then:

    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);     ... 

You may be able to do this with slightly less code, but I mostly copy/pasted from a custom component where it made sense to build-up the objects in the way shown above.



回答7:

If you have a javax.net.ssl.SSLSocket class reference in your code, you can set the enabled TLS protocols by a call to SSLSocket.setEnabledProtocols():

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); } 


回答8:

You could just specify the following property -Dhttps.protocols=TLSv1.1,TLSv1.2 at your server which configures the JVM to specify which TLS protocol version should be used during all https connections from client.



回答9:

Using -Dhttps.protocols=TLSv1.2 JVM argument didn't work for me. What worked is the following code

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(); 

Use the following JVM argument to verify

-Djavax.net.debug=all 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!