java - Cómo configurar la versión TLS en Apache HttpClient
ssl apache-httpclient-4.x (10)
Así es como lo hice funcionar en httpClient 4.5 (según la solicitud de 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;
¿Cómo puedo cambiar las versiones compatibles de TLS en mi HttpClient?
Estoy haciendo:
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);
Pero cuando reviso el socket creado, todavía dice que los protocolos compatibles son TLSv1.0, TLSv1.1 y TLSv1.2.
En realidad, solo quiero que deje de usar TLSv1.2, para este HttpClient específico.
Dado que esto solo apareció oculto en los comentarios, difícil de encontrar como solución:
Puede usar
java -Dhttps.protocols=TLSv1,TLSv1.1
, pero también debe usar
useSystemProperties()
client = HttpClientBuilder.create().useSystemProperties();
Usamos esta configuración en nuestro sistema ahora ya que esto nos permite configurar esto solo para algún uso del código.
En nuestro caso, todavía tenemos algo de Java 7 en ejecución y un punto final de API no permitido TLSv1, por lo que usamos
java -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2
para habilitar las versiones actuales de TLS.
Gracias @jebeaudet por señalar en esta dirección.
El uso de -Dhttps.protocols = TLSv1.2 JVM argumento no funcionó para mí. Lo que funcionó es el siguiente código
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();
Utilice el siguiente argumento JVM para verificar
-Djavax.net.debug=all
HttpClient-4.5, use TLSv1.2, debe codificar así:
//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();
}
}
La solucion es:
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();
Sin embargo, esto requiere org.apache.httpcomponents.httpclient 4.3.x.
Para HttpClient-4.1 usando TLSv1.2, el código sería algo como esto:
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.
Si está utilizando httpclient 4.2, debe escribir un pequeño código adicional.
Quería poder personalizar tanto los "protocolos habilitados para TLS" (por ejemplo,
TLSv1.1
específicamente, y ni
TLSv1
ni
TLSv1.2
), así como los conjuntos de
cifrado
.
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);
}
}
Entonces:
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);
...
Es posible que pueda hacer esto con un poco menos de código, pero principalmente copié / pegué desde un componente personalizado donde tenía sentido construir los objetos de la manera que se muestra arriba.
Si tiene una referencia de clase javax.net.ssl.SSLSocket en su código, puede establecer los protocolos TLS habilitados mediante una llamada a 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);
}
Simplemente puede especificar la siguiente propiedad -Dhttps.protocols = TLSv1.1, TLSv1.2 en su servidor que configura la JVM para especificar qué versión del protocolo TLS debe usarse durante todas las conexiones https desde el cliente.
Uso de
HttpClientBuilder
en HttpClient 4.5.x con un
HttpClientConnectionManager
personalizado con los valores predeterminados de
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()
Sin un
HttpClientConnectionManager
personalizado:
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(SSLContexts.createDefault(),
new String[] { "TLSv1.2" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build()