Saltar al contenido

Ignorando el certificado SSL en Apache HttpClient 4.3

Si te encuentras con algún detalle que no entiendes puedes dejarlo en la sección de comentarios y haremos todo lo necesario de ayudarte rápidamente.

Solución:

El siguiente código funciona para confiar en certificados autofirmados. Debe utilizar TrustSelfSignedStrategy al crear su 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 incluí el SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER a propósito: El objetivo era permitir las pruebas con certificados autofirmados para que no tenga que adquirir un certificado adecuado de una autoridad de certificación. Puede crear fácilmente un certificado autofirmado con el nombre de host correcto, así que hágalo en lugar de agregar el SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER bandera.

Si está utilizando el procedimiento PoolingHttpClientConnectionManager anterior no funciona, se ignora el SSLContext personalizado. 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();

así como. (ALLOW_ALL_HOSTNAME_VERIFIER está obsoleto).

Advertencia obligatoria: realmente no debería 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 al código dado 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 se probó usando


    org.apache.httpcomponents
    httpclient
    4.5.3

Y para los interesados, 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)

Al final de todo puedes encontrar las reseñas de otros programadores, tú igualmente tienes la libertad de insertar el tuyo si lo crees conveniente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *