it-swarm.com.de

SSL-Zertifikat in Apache HttpClient 4.3 ignorieren

Wie ignoriere ich das SSL-Zertifikat (allen vertrauen) für Apache HttpClient 4.3 ?

Alle Antworten, die ich in SO gefunden habe, behandeln frühere Versionen und die API wurde geändert.

Verbunden:

Bearbeiten:

  • Es ist nur zu Testzwecken. Kinder, versuche es nicht zu Hause (oder in der Produktion)
88
Jakub M.

Der folgende Code funktioniert für das Vertrauen von selbstsignierten Zertifikaten. Sie müssen die DataSelfSignedStrategy verwenden, wenn Sie Ihren Client erstellen:

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

Ich habe den SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER nicht mit Absicht hinzugefügt: Es ging darum, das Testen mit selbstsignierten Zertifikaten zuzulassen, damit Sie kein ordnungsgemäßes Zertifikat von einer Zertifizierungsstelle erwerben müssen. Sie können auf einfache Weise ein selbstsigniertes Zertifikat mit dem richtigen Hostnamen erstellen. Fügen Sie daher das Flag SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER hinzu.

131
mavroprovato

Wenn Sie die oben beschriebene PoolingHttpClientConnectionManager-Prozedur nicht verwenden, wird benutzerdefinierter SSLContext ignoriert. Beim Erstellen von PoolingHttpClientConnectionManager müssen Sie socketFactoryRegistry in contructor übergeben.

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<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
        .<ConnectionSocketFactory> create().register("https", sslsf)
        .build();

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
        socketFactoryRegistry);
CloseableHttpClient httpclient = HttpClients.custom()
        .setConnectionManager(cm).build();
83
vasekt

Als Zusatz zur Antwort von @mavroprovato: Wenn Sie allen Zertifikaten statt nur selbstsigniert vertrauen möchten, müssen Sie dies tun (im Stil Ihres Codes).

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

oder (direktes Kopieren und Einfügen aus meinem eigenen Code):

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

Wenn Sie auch die Überprüfung des Hostnamens überspringen möchten, müssen Sie dies festlegen 

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

auch. (ALLOW_ALL_HOSTNAME_VERIFIER ist veraltet).

Obligatorische Warnung: Sie sollten dies nicht wirklich tun, alle Zertifikate zu akzeptieren ist eine schlechte Sache. Es gibt jedoch einige seltene Anwendungsfälle, in denen Sie dies tun möchten.

Als Hinweis für den zuvor angegebenen Code möchten Sie die Antwort auch dann schließen, wenn httpclient.execute () eine Ausnahme auslöst

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

Code oben wurde mit getestet

<dependency>
    <groupId>org.Apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.3</version>
</dependency>

Und für Interessierte hier mein kompletter Testsatz:

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

(Arbeitsprüfprojekt in github )

27
eis

Eine kleine Ergänzung zur Antwort von vasekt:

Die mitgelieferte Lösung mit SocketFactoryRegistry funktioniert bei Verwendung von PoolingHttpClientConnectionManager.

Verbindungen über normales http funktionieren dann jedoch nicht mehr. Sie müssen zusätzlich eine PlainConnectionSocketFactory für das http-Protokoll hinzufügen, damit sie wieder funktionieren: 

Registry<ConnectionSocketFactory> socketFactoryRegistry = 
  RegistryBuilder.<ConnectionSocketFactory> create()
  .register("https", sslsf)
  .register("http", new PlainConnectionSocketFactory()).build();
19
migo

Nachdem Sie verschiedene Optionen ausprobiert hatten, funktionierte die folgende Konfiguration für http und https

        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);


        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>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();

Ich benutze http-client 4.3.3 -

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

13
Saurabh

Einfacher und kürzerer Arbeitscode:

Wir verwenden HTTPClient 4.3.5 und wir haben fast alle Lösungen aus dem Stackoverflow ausprobiert. Nachdem wir das Problem durchdacht und herausgefunden haben, kommen wir zum folgenden Code, der perfekt funktioniert. Fügen Sie es einfach hinzu, bevor Sie die HttpClient-Instanz erstellen.

eine Methode, mit der Sie eine Nachanfrage stellen ...

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

rufen Sie weiter auf und verwenden Sie die HttpPost-Instanz in der normalen Form

6
Hamed MP

Hier ist eine funktionierende Destillation der obigen Techniken, die "curl -insecure" entspricht:

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();
}
5
divbyzero

Bei Verwendung von HTTP-Client 4.5 musste ich den javasx.net.ssl.HostnameVerifier verwenden, um einen beliebigen Hostnamen (zu Testzwecken) zuzulassen. Folgendes habe ich am Ende getan:

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);
        }
    }
5
Kurt

Auf PoolingHttpClientConnectionManager zusammen mit Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslFactory).build();.__ Wenn Sie einen asynchronen httpclient mit PoolingNHttpClientConnectionManager verwenden möchten, sollte der Code wie folgt aussehen

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<SchemeIOSessionStrategy> sslioSessionRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create().register("https", sslioSessionStrategy).build();
PoolingNHttpClientConnectionManager ncm  = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(),sslioSessionRegistry);
CloseableHttpAsyncClient asyncHttpClient = HttpAsyncClients.custom().setConnectionManager(ncm).build();
asyncHttpClient.start();        

Wenn SieHttpClient 4.5.xverwenden, kann Ihr Code dem folgenden ähneln:

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();
2
Paul Vargas
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;
            }
        };
    }
}
2
Dahai Li

(Ich hätte direkt zu vasekt's Antwort einen Kommentar hinzugefügt, aber ich habe nicht genügend Reputationspunkte (da ist die Logik nicht sicher)

Wie auch immer ... was ich sagen wollte, ist, dass, selbst wenn Sie nicht explizit eine PoolingConnection erstellen/verlangen, nicht bedeutet, dass Sie keine bekommen.

Ich wurde verrückt, als ich versuchte herauszufinden, warum die ursprüngliche Lösung für mich nicht funktionierte, aber ich ignorierte die Antwort von Vasekt, da sie "nicht auf meinen Fall zutraf" - falsch! 

Ich starrte auf meine Stack-Spur, als tief und ich sah eine PoolingConnection in der Mitte. Bang - ich bin müde und Erfolg !! (unsere Demo ist morgen und ich wurde verzweifelt) :-) 

1
rich95

Vertrauen Sie allen Zertifikaten im 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());
1
Jeff Z

Sie können das folgende Code-Snippet verwenden, um die HttpClient-Instanz ohne Überprüfung der SSL-Zertifizierung abzurufen.

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<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>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();
    }
0
Radadiya Nikunj