可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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