Cómo ignorar los errores de certificado SSL en Apache HttpClient 4.0

125

¿Cómo evito errores de certificado SSL no válidos con Apache HttpClient 4.0?

Viet
fuente
12
Cabe señalar que las respuestas a esta pregunta no hacen más de lo que se pregunta: le permiten ignorar el error pero no solucionan el problema subyacente (un poco como quitar las baterías de una alarma de humo en lugar de apagar el incendio) ) Los certificados tienen el propósito de garantizar la seguridad de la conexión SSL / TLS, ignorar esos errores introduce una vulnerabilidad al ataque MITM. Use certificados de prueba en lugar de ignorar el error.
Bruno
46
"como quitar las baterías de una alarma de humo" Puede dar a otros desarrolladores el beneficio de la duda y asumir que saben lo que están haciendo. Quizás la motivación para esta pregunta son las pruebas locales y el OP desea realizar una prueba rápida sin pasar por las horribles cantidades de repeticiones de Java necesarias para configurar incluso un entorno SSL simple. Tal vez alguien podría responder la pregunta sin entrar en una conferencia "más sagrada que tú".
Mike
Es decir, en nuestra empresa, el servidor interno JIRA tiene un "certificado basado en la política de seguridad de Windows" que es válido en máquinas Windows incluidas en el dominio y no válido en otro. No puedo controlar esta política y todavía quiero llamar a JIRA REST API.
odiszapc
1
@Bruno La incapacidad de deshabilitar los detectores de humo durante un período de 30-60 minutos mientras se trata de un pequeño incendio en la cocina muestra una increíble falta de conocimiento sobre los patrones de uso por parte de algún funcionario legal en algún momento que siento que es ilegal. El hecho de que existe el concepto de "quitar las baterías de una alarma de humo" lo demuestra. Siento el mismo nivel de enojo por tener que obtener certificados para trabajar para una prueba simple que sé que no tiene ramificaciones de seguridad. La existencia de esta pregunta lo prueba.
Bill K

Respuestas:

84

Debe crear un SSLContext con su propio TrustManager y crear un esquema HTTPS utilizando este contexto. Aquí está el código

SSLContext sslContext = SSLContext.getInstance("SSL");

// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                    System.out.println("getAcceptedIssuers =============");
                    return null;
            }

            public void checkClientTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkClientTrusted =============");
            }

            public void checkServerTrusted(X509Certificate[] certs,
                            String authType) {
                    System.out.println("checkServerTrusted =============");
            }
} }, new SecureRandom());

SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);

// apache HttpClient version >4.2 should use BasicClientConnectionManager
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(cm);
Codificador ZZ
fuente
1
Digamos que no quiero comprar un certificado SSL válido para mi sitio y solo quiero usarlo, ¿este código puede ayudar? ¿Cómo es que no veo ninguna parte donde se necesita una URL o se necesita un manejo de excepciones?
Vie
19
Hmm, me dice que 'new SSLSocketFactory (ssslCont)' espera un KeyStore, no un SSLContext. ¿Me estoy perdiendo de algo?
MSpeed
2
Recibo el error de que un X509TrustManager no se puede transmitir a un TrustManager.
MW.
2
Asegúrese de importar los paquetes correctos, es decir, desde org.apache.http.
Guardián
2
¿Alguien sabe cómo combinar todo esto usando HttpClientBuilder?
Ali
112

Todas las otras respuestas quedaron en desuso o no funcionaron para HttpClient 4.3.

Aquí hay una manera de permitir todos los nombres de host al crear un cliente http.

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setHostnameVerifier(AllowAllHostnameVerifier.INSTANCE)
    .build();

O si está utilizando la versión 4.4 o posterior, la llamada actualizada se ve así:

CloseableHttpClient httpClient = HttpClients
    .custom()
    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
    .build();
erversteeg
fuente
Gracias por la respuesta, me gustaría saber de qué paquete son HttpsClients, ya que estoy usando en la compilación de Android ("org.apache.httpcomponents: httpclient: 4.3.4") pero esta clase no aparece.
Juan Saravia
1
Su paquete es org.apache.http.impl.client.HttpClients.
erversteeg
14
Esto funciona alrededor de una falta de coincidencia del nombre de host (supongo), pero no parece funcionar cuando el certificado no está firmado por una autoridad confiable.
twm
1
@twm por eso dice que "permite todos los nombres de host", los problemas de confianza requieren una configuración diferente.
eis
1
@eis, estaba señalando que esta respuesta aborda la pregunta original en ciertos casos pero no en otros.
twm
43

Solo tuve que hacer esto con el HttpClient 4.5 más nuevo y parece que han dejado de usar algunas cosas desde 4.4, así que aquí está el fragmento que funciona para mí y utiliza la API más reciente:

final SSLContext sslContext = new SSLContextBuilder()
        .loadTrustMaterial(null, (x509CertChain, authType) -> true)
        .build();

return HttpClientBuilder.create()
        .setSSLContext(sslContext)
        .setConnectionManager(
                new PoolingHttpClientConnectionManager(
                        RegistryBuilder.<ConnectionSocketFactory>create()
                                .register("http", PlainConnectionSocketFactory.INSTANCE)
                                .register("https", new SSLConnectionSocketFactory(sslContext,
                                        NoopHostnameVerifier.INSTANCE))
                                .build()
                ))
        .build();
Z4-
fuente
También funcionó para mí para httpclient 4.5.2
Vikas Ranjan
este está actualizado para HttpClient 4.5
Eres increíble el
31

Solo para el registro, hay una manera mucho más simple de lograr lo mismo con HttpClient 4.1

    SSLSocketFactory sslsf = new SSLSocketFactory(new TrustStrategy() {

        public boolean isTrusted(
                final X509Certificate[] chain, String authType) throws CertificateException {
            // Oh, I am easy...
            return true;
        }

    });
ok2c
fuente
1
¿Te falta algún código en este ejemplo? Tal vez una llamada a httpClient.set ...?
Gray
66
httpclient.getConnectionManager (). getSchemeRegistry (). register (nuevo esquema ("https", 443, sslsf));
Ben Flynn
8
SSLSocketFactory está en desuso en HttpClient 4.3
Toilal
1
Si usa Java 8, puede inclusonew SSLSocketFactory((chain, authType) -> true);
jlb
28

Apache HttpClient 4.5.5

HttpClient httpClient = HttpClients
            .custom()
            .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
            .build();

No se ha utilizado ninguna API obsoleta.

Caso de prueba verificable simple:

package org.apache.http.client.test;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

public class ApacheHttpClientTest {

    private HttpClient httpClient;

    @Before
    public void initClient() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
        httpClient = HttpClients
                .custom()
                .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
    }

    @Test
    public void apacheHttpClient455Test() throws IOException {
        executeRequestAndVerifyStatusIsOk("https://expired.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://wrong.host.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://self-signed.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://untrusted-root.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://revoked.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://pinning-test.badssl.com");
        executeRequestAndVerifyStatusIsOk("https://sha1-intermediate.badssl.com");
    }

    private void executeRequestAndVerifyStatusIsOk(String url) throws IOException {
        HttpUriRequest request = new HttpGet(url);

        HttpResponse response = httpClient.execute(request);
        int statusCode = response.getStatusLine().getStatusCode();

        assert statusCode == 200;
    }
}
Mikhail Kholodkov
fuente
¡Gracias! Simplemente cambie TrustAllStrategy.INSTANCEcon TrustSelfSignedStrategy.INSTANCEen esta respuesta.
Percy Vega
Esto no funcionó para mí. javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: error de construcción de ruta PKIX: sun.security. provider.certpath.SunCertPathBuilderException: no se puede encontrar la ruta de certificación válida para el objetivo solicitado
ggb667
26

Para el registro, probado con httpclient 4.3.6 y compatible con Executor de fluida api:

CloseableHttpClient httpClient = HttpClients.custom().
                    setHostnameVerifier(new AllowAllHostnameVerifier()).
                    setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
                    {
                        public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
                        {
                            return true;
                        }
                    }).build()).build();
STM
fuente
3
Para HttpClient 4.4 hacia arriba, debe hacer esto, y también puede necesitar crear un SSLConnectionSocketFactoryuso de eso SSLContexty definirlo en a Registry<ConnectionSocketFactory>, si va a crear un PoolingHttpClientConnectionManager. Las otras respuestas son más populares, pero no funcionan en HttpClient 4.4.
Thomas W
1
Funciona exactamente así con httpclient-4.3.5.jar.
Harald
18

Para Apache HttpClient 4.4:

HttpClientBuilder b = HttpClientBuilder.create();

SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
        return true;
    }
}).build();
b.setSslcontext( sslContext);

// or SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken
HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.getSocketFactory())
        .register("https", sslSocketFactory)
        .build();

// allows multi-threaded use
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry);
b.setConnectionManager( connMgr);

HttpClient client = b.build();

Esto se extrae de nuestra implementación de trabajo real.

Las otras respuestas son populares, pero para HttpClient 4.4 no funcionan. Pasé horas probando y agotando las posibilidades, pero parece que hubo un cambio y reubicación de API extremadamente importante en 4.4.

Consulte también una explicación un poco más completa en: http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/

¡Espero que ayude!

Thomas W
fuente
2
Era ese bit de SSLContext que necesitaba. Muy obligado.
muttonUp
14

Si todo lo que quiere hacer es deshacerse de los errores de nombre de host no válidos, simplemente puede hacer:

HttpClient httpClient = new DefaultHttpClient();
SSLSocketFactory sf = (SSLSocketFactory)httpClient.getConnectionManager()
    .getSchemeRegistry().getScheme("https").getSocketFactory();
sf.setHostnameVerifier(new AllowAllHostnameVerifier());
David Tinker
fuente
8
El método sf.setHostnameVerifier ha quedado en desuso a partir de 4.1. La alternativa es usar uno de los constructores. Por ejemplo:SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
kaliatech
Esto fue muy útil cuando tuve que lidiar con el código heredado.
DuncanSungWKim
9

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égalo antes de crear la instancia de HttpClient.

algún método para llamar al hacer solicitudes de publicación ...

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

continúe su solicitud en la forma normal

MP Hamed
fuente
7

Con fluidez 4.5.2 tuve que hacer la siguiente modificación para que funcione.

try {
    TrustManager[] trustAllCerts = new TrustManager[] {
       new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }
    public void checkClientTrusted(X509Certificate[] certs, String authType) {  }

    public void checkServerTrusted(X509Certificate[] certs, String authType) {  }
    }
    };

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new SecureRandom());
    CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setSslcontext(sc).build();

    String output = Executor.newInstance(httpClient).execute(Request.Get("https://127.0.0.1:3000/something")
                                      .connectTimeout(1000)
                                      .socketTimeout(1000)).returnContent().asString();
    } catch (Exception e) {
    }
Talespin_Kit
fuente
1
Esta es la única solución que funcionó para mí. Probé las soluciones anteriores para 4.3 y 4.4 antes de actualizar a 4.5 y probar esto.
dirkoneill
6

Así es como lo hice.

  1. Crear mi propio MockSSLSocketFactory (clase adjunta a continuación)
  2. Úselo para inicializar DefaultHttpClient. Se debe proporcionar la configuración del proxy si se usa un proxy.

Inicializando DefaultHTTPClient -

SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    schemeRegistry.register(new Scheme("https", 443, new MockSSLSocketFactory()));
    ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);

    DefaultHttpClient httpclient = new DefaultHttpClient(cm);

Simulacro de Fábrica SSL

public class MockSSLSocketFactory extends SSLSocketFactory {

public MockSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
    super(trustStrategy, hostnameVerifier);
}

private static final X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
    @Override
    public void verify(String host, SSLSocket ssl) throws IOException {
        // Do nothing
    }

    @Override
    public void verify(String host, X509Certificate cert) throws SSLException {
        //Do nothing
    }

    @Override
    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
        //Do nothing
    }

    @Override
    public boolean verify(String s, SSLSession sslSession) {
        return true; 
    }
};

private static final TrustStrategy trustStrategy = new TrustStrategy() {
    @Override
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        return true;
    }
};
}

Si está detrás de un proxy, debe hacer esto:

HttpParams params = new BasicHttpParams();
    params.setParameter(AuthPNames.PROXY_AUTH_PREF, getClientAuthPrefs());

DefaultHttpClient httpclient = new DefaultHttpClient(cm, params);

httpclient.getCredentialsProvider().setCredentials(
                        new AuthScope(proxyHost, proxyPort),
                        new UsernamePasswordCredentials(proxyUser, proxyPass));
Swaroop Rath
fuente
Sería útil si incluyera las importaciones en el futuro. Hay dos clases diferentes.
AndroidDev
4

En extensión a la respuesta de ZZ Coder, será bueno anular el hostnameverifier.

// ...
SSLSocketFactory sf = new SSLSocketFactory (sslContext);
sf.setHostnameVerifier(new X509HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }

    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
    }

    public void verify(String host, X509Certificate cert) throws SSLException {
    }

    public void verify(String host, SSLSocket ssl) throws IOException {
    }
});
// ...
eldur
fuente
Puede lograr lo mismo simplemente haciendosf.setHostnameVerifier(new AllowAllHostnameVerifier());
Dan Dyer,
77
El sf.setHostnameVerifier ha quedado en desuso a partir de 4.1. La alternativa es usar uno de los constructores. Por ejemplo:SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
kaliatech
4
        DefaultHttpClient httpclient = new DefaultHttpClient();

    SSLContext sslContext;
    try {
        sslContext = SSLContext.getInstance("SSL");

        // set up a TrustManager that trusts everything
        try {
            sslContext.init(null,
                    new TrustManager[] { new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
                            log.debug("getAcceptedIssuers =============");
                            return null;
                        }

                        public void checkClientTrusted(
                                X509Certificate[] certs, String authType) {
                            log.debug("checkClientTrusted =============");
                        }

                        public void checkServerTrusted(
                                X509Certificate[] certs, String authType) {
                            log.debug("checkServerTrusted =============");
                        }
                    } }, new SecureRandom());
        } catch (KeyManagementException e) {
        }
         SSLSocketFactory ssf = new SSLSocketFactory(sslContext,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
         ClientConnectionManager ccm = this.httpclient.getConnectionManager();
         SchemeRegistry sr = ccm.getSchemeRegistry();
         sr.register(new Scheme("https", 443, ssf));            
    } catch (Exception e) {
        log.error(e.getMessage(),e);
    }
pequeño tigre
fuente
4

Para aceptar todos los certificados en HttpClient 4.4.x, puede usar el siguiente revestimiento al crear el httpClient:

httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build()).build();
Frío
fuente
Estoy obteniendo esto: Causado por: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: ¿No hay nombres alternativos de sujeto presentes?
¿Cómo permitir conexiones a sitios SSL sin certificados en la API HttpClient o en la API RestClient?
4

Probado con HttpClient 4.5.5 con Fluent API

final SSLContext sslContext = new SSLContextBuilder()
    .loadTrustMaterial(null, (x509CertChain, authType) -> true).build();

CloseableHttpClient httpClient = HttpClients.custom()
    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
    .setSSLContext(sslContext).build();

String result = Executor.newInstance(httpClient)
    .execute(Request.Get("https://localhost:8080/someapi")
    .connectTimeout(1000).socketTimeout(1000))
    .returnContent().asString();
Lachesis
fuente
3

El siguiente código funciona con 4.5.5

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

class HttpsSSLClient {


    public static CloseableHttpClient createSSLInsecureClient() {
        SSLContext sslcontext = createSSLContext();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new HostnameVerifier() {

            @Override
            public boolean verify(String paramString, SSLSession paramSSLSession) {
                return true;
            }
        });
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        return httpclient;
    }


    private static SSLContext createSSLContext() {
        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContext.getInstance("TLS");
            sslcontext.init(null, new TrustManager[] {new TrustAnyTrustManager()}, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sslcontext;
    }


    private static class TrustAnyTrustManager implements X509TrustManager {

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
        }
    }

}
public class TestMe {


    public static void main(String[] args) throws IOException {
        CloseableHttpClient client = HttpsSSLClient.createSSLInsecureClient();

        CloseableHttpResponse res = client.execute(new HttpGet("https://wrong.host.badssl.com/"));
        System.out.println(EntityUtils.toString(res.getEntity()));
    }
}

La salida del código es

Código

La salida en el navegador es

SSL incorrecto

El pom utilizado está debajo

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tarun</groupId>
    <artifactId>testing</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
    <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.5</version>
    </dependency>

</dependencies>
</project>
Tarun Lalwani
fuente
gracias por la respuesta actualizada, le di la recompensa al nuevo chico por ser "acogedor" ¡pero solo quería respuestas actualizadas para todos!
1
@feelingunwelcome, claro. También lo he votado a él :-)
Tarun Lalwani
2

una versión de trabajo completa para Apache HttpClient 4.1.3 (basado en el código de oleg anterior, pero aún necesitaba un allow_all_hostname_verifier en mi sistema):

private static HttpClient trustEveryoneSslHttpClient() {
    try {
        SchemeRegistry registry = new SchemeRegistry();

        SSLSocketFactory socketFactory = new SSLSocketFactory(new TrustStrategy() {

            public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
                // Oh, I am easy...
                return true;
            }

        }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        registry.register(new Scheme("https", 443, socketFactory));
        ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
        DefaultHttpClient client = new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
        return client;
    } catch (GeneralSecurityException e) {
        throw new RuntimeException(e);
    }
}

Tenga en cuenta que vuelvo a lanzar todas las excepciones porque, en realidad, ¡no hay mucho que pueda hacer si algo de esto falla en un sistema real!

Korny
fuente
2

Si está utilizando la API fluida , debe configurarla a través de Executor:

Executor.unregisterScheme("https");
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslContext,
                                  SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Executor.registerScheme(new Scheme("https", 443, sslSocketFactory));

... donde sslContextse crea el SSLContext como se muestra en la respuesta del Codificador ZZ .

Después de eso, puede hacer sus solicitudes http como:

String responseAsString = Request.Get("https://192.168.1.0/whatever.json")
                         .execute().getContent().asString();

Nota: probado con HttpClient 4.2

Elias Dorneles
fuente
Desafortunadamente desaprobado en 4.3: "Desaprobado. (4.3) no utilizar"
STM
2

Probado con 4.3.3

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;

import org.apache.http.Header;
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.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class AccessProtectedResource {

public static void main(String[] args) throws Exception {

    // Trust all certs
    SSLContext sslcontext = buildSSLContext();

    // Allow TLSv1 protocol only
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslcontext,
            new String[] { "TLSv1" },
            null,
            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    CloseableHttpClient httpclient = HttpClients.custom()
            .setSSLSocketFactory(sslsf)
            .build();
    try {

        HttpGet httpget = new HttpGet("https://yoururl");

        System.out.println("executing request" + httpget.getRequestLine());

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            for (Header header : response.getAllHeaders()) {
                System.out.println(header);
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    } finally {
        httpclient.close();
    }
}

private static SSLContext buildSSLContext()
        throws NoSuchAlgorithmException, KeyManagementException,
        KeyStoreException {
    SSLContext sslcontext = SSLContexts.custom()
            .setSecureRandom(new SecureRandom())
            .loadTrustMaterial(null, new TrustStrategy() {

                public boolean isTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    return true;
                }
            })
            .build();
    return sslcontext;
}

}

artesano
fuente
¿Cómo establecer valores en encabezados si quisiera hacer eso?
2

Probado en 4.5.4:

            SSLContext sslContext = new SSLContextBuilder()
                    .loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true).build();

            CloseableHttpClient httpClient = HttpClients
                    .custom()
                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                    .setSSLContext(sslContext)
                    .build();
Jacky
fuente
0

Si encontró este problema al usar AmazonS3Client, que incorpora Apache HttpClient 4.1, simplemente necesita definir una propiedad del sistema como esta para que el comprobador de certificados SSL se relaje:

-Dcom.amazonaws.sdk.disableCertChecking = true

Travesura manejada

Mike Slinn
fuente
0

fwiw, un ejemplo que usa la implementación "RestEasy" de JAX-RS 2.x para construir un cliente especial "confíe en todos" ...

    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.security.GeneralSecurityException;
    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    import java.util.Arrays;
    import javax.ejb.Stateless;
    import javax.net.ssl.SSLContext;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import javax.ws.rs.client.Entity;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.HttpClientConnectionManager;
    import org.apache.http.conn.ssl.TrustStrategy;
    import org.jboss.resteasy.client.jaxrs.ResteasyClient;
    import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
    import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
    import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
    import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.ssl.NoopHostnameVerifier;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.ssl.SSLContexts;

    @Stateless
    @Path("/postservice")
    public class PostService {

        private static final Logger LOG = LogManager.getLogger("PostService");

        public PostService() {
        }

        @GET
        @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
        public PostRespDTO get() throws NoSuchAlgorithmException, KeyManagementException, MalformedURLException, IOException, GeneralSecurityException {

            //...object passed to the POST method...
            PostDTO requestObject = new PostDTO();
            requestObject.setEntryAList(new ArrayList<>(Arrays.asList("ITEM0000A", "ITEM0000B", "ITEM0000C")));
            requestObject.setEntryBList(new ArrayList<>(Arrays.asList("AAA", "BBB", "CCC")));

            //...build special "trust all" client to call POST method...
            ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(createTrustAllClient());

            ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
            ResteasyWebTarget target = client.target("https://localhost:7002/postRespWS").path("postrespservice");
            Response response = target.request().accept(MediaType.APPLICATION_JSON).post(Entity.entity(requestObject, MediaType.APPLICATION_JSON));

            //...object returned from the POST method...
            PostRespDTO responseObject = response.readEntity(PostRespDTO.class);

            response.close();

            return responseObject;
        }


        //...get special "trust all" client...
        private static CloseableHttpClient createTrustAllClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, TRUSTALLCERTS).useProtocol("TLS").build();
            HttpClientBuilder builder = HttpClientBuilder.create();
            NoopHostnameVerifier noop = new NoopHostnameVerifier();
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, noop);
            builder.setSSLSocketFactory(sslConnectionSocketFactory);
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionSocketFactory).build();
            HttpClientConnectionManager ccm = new BasicHttpClientConnectionManager(registry);
            builder.setConnectionManager(ccm);

            return builder.build();
        }


        private static final TrustStrategy TRUSTALLCERTS = new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
                return true;
            }
        };
    }

dependencias de Maven relacionadas

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-client</artifactId>
        <version>3.0.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>jaxrs-api</artifactId>
        <version>3.0.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson2-provider</artifactId>
        <version>3.0.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5</version>
        <type>jar</type>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency> 
Sairn
fuente
-1

Si está utilizando Apache httpClient 4.5.x intente esto:

public static void main(String... args)  {

    try (CloseableHttpClient httpclient = createAcceptSelfSignedCertificateClient()) {
        HttpGet httpget = new HttpGet("https://example.com");
        System.out.println("Executing request " + httpget.getRequestLine());

        httpclient.execute(httpget);
        System.out.println("----------------------------------------");
    } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException | IOException e) {
        throw new RuntimeException(e);
    }
}

private static CloseableHttpClient createAcceptSelfSignedCertificateClient()
        throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

    // use the TrustSelfSignedStrategy to allow Self Signed Certificates
    SSLContext sslContext = SSLContextBuilder
            .create()
            .loadTrustMaterial(new TrustSelfSignedStrategy())
            .build();

    // we can optionally disable hostname verification. 
    // if you don't want to further weaken the security, you don't have to include this.
    HostnameVerifier allowAllHosts = new NoopHostnameVerifier();

    // create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
    // and allow all hosts verifier.
    SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);

    // finally create the HttpClient using HttpClient factory methods and assign the ssl socket factory
    return HttpClients
            .custom()
            .setSSLSocketFactory(connectionFactory)
            .build();
}
Brijesh Patel
fuente