Ignorar el certificado SSL en Apache HttpClient 4.3

¿Cómo ignorar el certificado SSL (confiar en todo) para Apache HttpClient 4.3 ?

Todas las respuestas que he encontrado en SO tratan versiones anteriores, y la API cambió.

Relacionado:

  • Cómo ignorar los errores del certificado SSL en Apache HttpClient 4.0
  • ¿Cómo manejar certificados SSL inválidos con Apache HttpClient?
  • Necesita confiar en todos los certificados durante el desarrollo usando Spring
  • Ignorar los errores del certificado SSL con Java

Editar:

  • Es solo para propósitos de prueba. Niños, no lo prueben en casa (ni en producción)

El siguiente código funciona para confiar en los certificados autofirmados. Debes usar el TrustSelfSignedStrategy al crear tu cliente:

SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( builder.build()); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory( sslsf).build(); HttpGet httpGet = new HttpGet("https://some-server"); CloseableHttpResponse response = httpclient.execute(httpGet); try { System.out.println(response.getStatusLine()); HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); } finally { response.close(); } 

No SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER el SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER a propósito: el objective era permitir las pruebas con certificados autofirmados, por lo que no es necesario adquirir un certificado adecuado de una autoridad de certificación. Puede crear fácilmente un certificado autofirmado con el nombre de host correcto, haga eso en lugar de agregar el indicador SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER .

Si está utilizando el procedimiento PoolingHttpClientConnectionManager anterior, no funciona, SSLContext personalizado se ignora. Debe pasar socketFactoryRegistry en contructor al crear PoolingHttpClientConnectionManager.

 SSLContextBuilder builder = SSLContexts.custom(); builder.loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }); SSLContext sslContext = builder.build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext, new X509HostnameVerifier() { @Override public void verify(String host, SSLSocket ssl) throws IOException { } @Override public void verify(String host, X509Certificate cert) throws SSLException { } @Override public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { } @Override public boolean verify(String s, SSLSession sslSession) { return true; } }); Registry socketFactoryRegistry = RegistryBuilder . create().register("https", sslsf) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager( socketFactoryRegistry); CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(cm).build(); 

Como una adición a la respuesta de @mavroprovato, si desea confiar en todos los certificados en lugar de solo autofirmados, lo haría (en el estilo de su código)

 builder.loadTrustMaterial(null, new TrustStrategy(){ public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }); 

o (copiar y pegar directamente desde mi propio código):

 import javax.net.ssl.SSLContext; import org.apache.http.ssl.TrustStrategy; import org.apache.http.ssl.SSLContexts; // ... SSLContext sslContext = SSLContexts .custom() //FIXME to contain real trust store .loadTrustMaterial(new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }) .build(); 

Y si también desea omitir la verificación del nombre de host, debe configurar

  CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory( sslsf).setSSLHostnameVerifier( NoopHostnameVerifier.INSTANCE).build(); 

también. (ALLOW_ALL_HOSTNAME_VERIFIER está en desuso).

Advertencia obligatoria: no deberías hacer esto, aceptar todos los certificados es algo malo. Sin embargo, hay algunos casos de uso poco comunes en los que desea hacer esto.

Como nota del código proporcionado anteriormente, querrá cerrar la respuesta incluso si httpclient.execute () arroja una excepción

 CloseableHttpResponse response = null; try { response = httpclient.execute(httpGet); System.out.println(response.getStatusLine()); HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); } finally { if (response != null) { response.close(); } } 

El código anterior fue probado usando

  org.apache.httpcomponents httpclient 4.5.3  

Y para el interesado, aquí está mi conjunto de prueba completo:

 import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustStrategy; import org.apache.http.util.EntityUtils; import org.junit.Test; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLPeerUnverifiedException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class TrustAllCertificatesTest { final String expiredCertSite = "https://expired.badssl.com/"; final String selfSignedCertSite = "https://self-signed.badssl.com/"; final String wrongHostCertSite = "https://wrong.host.badssl.com/"; static final TrustStrategy trustSelfSignedStrategy = new TrustSelfSignedStrategy(); static final TrustStrategy trustAllStrategy = new TrustStrategy(){ public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }; @Test public void testSelfSignedOnSelfSignedUsingCode() throws Exception { doGet(selfSignedCertSite, trustSelfSignedStrategy); } @Test(expected = SSLHandshakeException.class) public void testExpiredOnSelfSignedUsingCode() throws Exception { doGet(expiredCertSite, trustSelfSignedStrategy); } @Test(expected = SSLPeerUnverifiedException.class) public void testWrongHostOnSelfSignedUsingCode() throws Exception { doGet(wrongHostCertSite, trustSelfSignedStrategy); } @Test public void testSelfSignedOnTrustAllUsingCode() throws Exception { doGet(selfSignedCertSite, trustAllStrategy); } @Test public void testExpiredOnTrustAllUsingCode() throws Exception { doGet(expiredCertSite, trustAllStrategy); } @Test(expected = SSLPeerUnverifiedException.class) public void testWrongHostOnTrustAllUsingCode() throws Exception { doGet(wrongHostCertSite, trustAllStrategy); } @Test public void testSelfSignedOnAllowAllUsingCode() throws Exception { doGet(selfSignedCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE); } @Test public void testExpiredOnAllowAllUsingCode() throws Exception { doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE); } @Test public void testWrongHostOnAllowAllUsingCode() throws Exception { doGet(expiredCertSite, trustAllStrategy, NoopHostnameVerifier.INSTANCE); } public void doGet(String url, TrustStrategy trustStrategy, HostnameVerifier hostnameVerifier) throws Exception { SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(trustStrategy); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( builder.build()); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory( sslsf).setSSLHostnameVerifier(hostnameVerifier).build(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpclient.execute(httpGet); try { System.out.println(response.getStatusLine()); HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); } finally { response.close(); } } public void doGet(String url, TrustStrategy trustStrategy) throws Exception { SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(trustStrategy); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( builder.build()); CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory( sslsf).build(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpclient.execute(httpGet); try { System.out.println(response.getStatusLine()); HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); } finally { response.close(); } } } 

(proyecto de prueba de trabajo en github )

Una pequeña adición a la respuesta de vasekt:

La solución proporcionada con SocketFactoryRegistry funciona cuando se usa PoolingHttpClientConnectionManager.

Sin embargo, las conexiones a través de http simple ya no funcionan. También debe agregar PlainConnectionSocketFactory para el protocolo http para que funcionen nuevamente:

 Registry socketFactoryRegistry = RegistryBuilder. create() .register("https", sslsf) .register("http", new PlainConnectionSocketFactory()).build(); 

Después de probar varias opciones, la siguiente configuración funcionó para http y https

  SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); Registry registry = RegistryBuilder.create() .register("http", new PlainConnectionSocketFactory()) .register("https", sslsf) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); cm.setMaxTotal(2000);//max connection //System.setProperty("jsse.enableSNIExtension", "false"); //"" CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(sslsf) .setConnectionManager(cm) .build(); 

Estoy usando http-client 4.3.3 –

compile 'org.apache.httpcomponents:httpclient:4.3.3'

Código de trabajo más simple y más corto:

Estamos usando HTTPClient 4.3.5 y probamos que casi todas las soluciones existen en el stackoverflow pero nada. Después de pensar y resolver el problema, llegamos al siguiente código que funciona perfectamente, solo agréguelo antes de crear la instancia de HttpClient.

algún método que usas para hacer una solicitud posterior …

 SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }); SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(builder.build(), SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslSF).build(); HttpPost postRequest = new HttpPost(url); 

continuar llamando y usando la instancia de HttpPost en la forma normal

Al usar http client 4.5 tuve que usar javasx.net.ssl.HostnameVerifier para permitir cualquier nombre de host (para fines de prueba). Esto es lo que terminé haciendo:

 CloseableHttpClient httpClient = null; try { SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); HostnameVerifier hostnameVerifierAllowAll = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build(), hostnameVerifierAllowAll); CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( new AuthScope("192.168.30.34", 8443), new UsernamePasswordCredentials("root", "password")); httpClient = HttpClients.custom() .setSSLSocketFactory(sslSocketFactory) .setDefaultCredentialsProvider(credsProvider) .build(); HttpGet httpGet = new HttpGet("https://192.168.30.34:8443/axis/services/getStuff?firstResult=0&maxResults=1000"); CloseableHttpResponse response = httpClient.execute(httpGet); int httpStatus = response.getStatusLine().getStatusCode(); if (httpStatus >= 200 && httpStatus < 300) { [...] } else { throw new ClientProtocolException("Unexpected response status: " + httpStatus); } } catch (Exception ex) { ex.printStackTrace(); } finally { try { httpClient.close(); } catch (IOException ex) { logger.error("Error while closing the HTTP client: ", ex); } } 

Aquí hay una destilación de trabajo de las técnicas anteriores, equivalente a “curl –insecure”:

 HttpClient getInsecureHttpClient() throws GeneralSecurityException { TrustStrategy trustStrategy = new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) { return true; } }; HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }; return HttpClients.custom() .setSSLSocketFactory(new SSLConnectionSocketFactory( new SSLContextBuilder().loadTrustMaterial(trustStrategy).build(), hostnameVerifier)) .build(); } 

Además de PoolingHttpClientConnectionManager junto con el Registry socketFactoryRegistry = RegistryBuilder. create().register("https", sslFactory).build(); Si desea un httpclient asincrónico utilizando PoolingNHttpClientConnectionManager el código debería ser similar al siguiente

 SSLContextBuilder builder = SSLContexts.custom(); builder.loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }); SSLContext sslContext = builder.build(); SchemeIOSessionStrategy sslioSessionStrategy = new SSLIOSessionStrategy(sslContext, new HostnameVerifier(){ @Override public boolean verify(String hostname, SSLSession session) { return true;// TODO as of now allow all hostnames } }); Registry sslioSessionRegistry = RegistryBuilder.create().register("https", sslioSessionStrategy).build(); PoolingNHttpClientConnectionManager ncm = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(),sslioSessionRegistry); CloseableHttpAsyncClient asyncHttpClient = HttpAsyncClients.custom().setConnectionManager(ncm).build(); asyncHttpClient.start(); 
 class ApacheHttpClient { /*** * This is a https get request that bypasses certificate checking and hostname verifier. * It uses basis authentication method. * It is tested with Apache httpclient-4.4. * It dumps the contents of a https page on the console output. * It is very similar to http get request, but with the additional customization of * - credential provider, and * - SSLConnectionSocketFactory to bypass certification checking and hostname verifier. * @param path String * @param username String * @param password String * @throws IOException */ public void get(String path, String username, String password) throws IOException { final CloseableHttpClient httpClient = HttpClients.custom() .setDefaultCredentialsProvider(createCredsProvider(username, password)) .setSSLSocketFactory(createGenerousSSLSocketFactory()) .build(); final CloseableHttpResponse response = httpClient.execute(new HttpGet(path)); try { HttpEntity entity = response.getEntity(); if (entity == null) return; System.out.println(EntityUtils.toString(entity)); } finally { response.close(); httpClient.close(); } } private CredentialsProvider createCredsProvider(String username, String password) { CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( AuthScope.ANY, new UsernamePasswordCredentials(username, password)); return credsProvider; } /*** * * @return SSLConnectionSocketFactory that bypass certificate check and bypass HostnameVerifier */ private SSLConnectionSocketFactory createGenerousSSLSocketFactory() { SSLContext sslContext; try { sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, new TrustManager[]{createGenerousTrustManager()}, new SecureRandom()); } catch (KeyManagementException | NoSuchAlgorithmException e) { e.printStackTrace(); return null; } return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); } private X509TrustManager createGenerousTrustManager() { return new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] cert, String s) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] cert, String s) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; } } 

(Hubiera agregado un comentario directamente a la respuesta de vasekt, pero no tengo suficientes puntos de reputación (no estoy seguro de la lógica)

De todos modos … lo que quería decir es que incluso si no estás creando / solicitando una PoolingConnection explícitamente, no significa que no la estés obteniendo.

Me estaba volviendo loca intentar descubrir por qué la solución original no me funcionaba, pero ignoré la respuesta de Vasekt ya que “no se aplicaba a mi caso”, ¡mal!

Estaba mirando mi rastro de stack cuando estaba bajo y he aquí que vi una PoolingConnection en el medio. Bang – ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡Su adición y éxito (nuestra demostración es mañana y estaba desesperado) 🙂

Confiar en todos los certificados en Apache HTTP Client

 TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sc); httpclient = HttpClients.custom().setSSLSocketFactory( sslsf).build(); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

Puede usar el siguiente fragmento de código para obtener la instancia HttpClient sin verificación de certificación SSL.

 private HttpClient getSSLHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { LogLoader.serverLog.trace("In getSSLHttpClient()"); SSLContext context = SSLContext.getInstance("SSL"); TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; context.init(null, new TrustManager[] { tm }, null); HttpClientBuilder builder = HttpClientBuilder.create(); SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(context); builder.setSSLSocketFactory(sslConnectionFactory); PlainConnectionSocketFactory plainConnectionSocketFactory = new PlainConnectionSocketFactory(); Registry registry = RegistryBuilder.create() .register("https", sslConnectionFactory).register("http", plainConnectionSocketFactory).build(); PoolingHttpClientConnectionManager ccm = new PoolingHttpClientConnectionManager(registry); ccm.setMaxTotal(BaseConstant.CONNECTION_POOL_SIZE); ccm.setDefaultMaxPerRoute(BaseConstant.CONNECTION_POOL_SIZE); builder.setConnectionManager((HttpClientConnectionManager) ccm); builder.disableRedirectHandling(); LogLoader.serverLog.trace("Out getSSLHttpClient()"); return builder.build(); } 

Si está utilizando HttpClient 4.5.x , su código puede ser similar al siguiente:

 SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, TrustSelfSignedStrategy.INSTANCE).build(); SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( sslContext, NoopHostnameVerifier.INSTANCE); HttpClient httpClient = HttpClients.custom() .setDefaultCookieStore(new BasicCookieStore()) .setSSLSocketFactory(sslSocketFactory) .build(); 
Intereting Posts