HttpClient mit SSL

1. Übersicht

Dieser Artikel zeigt, wie Sie den Apache HttpClient 4 mit der SSL-Unterstützung "Alle akzeptieren" konfigurieren . Das Ziel ist einfach: Verwenden Sie HTTPS-URLs ohne gültige Zertifikate.

Wenn Sie tiefer graben und andere coole Dinge lernen möchten, die Sie mit dem HttpClient tun können, gehen Sie zum Haupthandbuch für HttpClient .

2. Die SSLPeerUnverifiedException

Ohne die Konfiguration von SSL mit dem HttpClient schlägt der folgende Test fehl, bei dem eine HTTPS-URL verwendet wird:

public class RestClientLiveManualTest { @Test(expected = SSLPeerUnverifiedException.class) public void whenHttpsUrlIsConsumed_thenException() throws ClientProtocolException, IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); String urlOverHttps = "//localhost:8082/httpclient-simple"; HttpGet getMethod = new HttpGet(urlOverHttps); HttpResponse response = httpClient.execute(getMethod); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); } }

Der genaue Fehler ist:

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397) at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126) ...

Die Ausnahme javax.net.ssl.SSLPeerUnverifiedException tritt immer dann auf, wenn für die URL keine gültige Vertrauenskette hergestellt werden konnte.

3. Konfigurieren Sie SSL - Akzeptieren Sie alle (HttpClient <4.3)

Lassen Sie uns nun den HTTP-Client so konfigurieren, dass er allen Zertifikatketten unabhängig von ihrer Gültigkeit vertraut:

@Test public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException { HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); CloseableHttpClient httpClient = (CloseableHttpClient) requestFactory.getHttpClient(); TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; SSLSocketFactory sf = new SSLSocketFactory(acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER); httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 8443, sf)); ResponseEntity response = new RestTemplate(requestFactory). exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }

Mit der neuen TrustStrategy, die jetzt den Standardprozess zur Zertifikatsüberprüfung überschreibt (der einen konfigurierten Vertrauensmanager konsultieren sollte), ist der Test nun erfolgreich und der Client kann die HTTPS-URL verwenden .

4. Konfigurieren Sie SSL - Alle akzeptieren (HttpClient 4.4 und höher)

Mit dem neuen HTTPClient haben wir jetzt einen erweiterten, neu gestalteten Standard-SSL-Hostnamen-Verifizierer. Mit der Einführung von SSLConnectionSocketFactory und RegistryBuilder ist es auch einfach, SSLSocketFactory zu erstellen. So können wir den obigen Testfall wie folgt schreiben:

@Test public final void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException { TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); Registry socketFactoryRegistry = RegistryBuilder. create() .register("https", sslsf) .register("http", new PlainConnectionSocketFactory()) .build(); BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf) .setConnectionManager(connectionManager).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); ResponseEntity response = new RestTemplate(requestFactory) .exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }

5. Das Spring RestTemplate mit SSL (HttpClient <4.3)

Nachdem wir nun gesehen haben, wie ein roher HttpClient mit SSL-Unterstützung konfiguriert wird , werfen wir einen Blick auf einen übergeordneten Client - das Spring RestTemplate .

Wenn kein SSL konfiguriert ist, schlägt der folgende Test wie erwartet fehl:

@Test(expected = ResourceAccessException.class) public void whenHttpsUrlIsConsumed_thenException() { String urlOverHttps = "//localhost:8443/httpclient-simple/api/bars/1"; ResponseEntity response = new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }

Konfigurieren wir also SSL:

@Test public void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenException() throws GeneralSecurityException { HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); DefaultHttpClient httpClient = (DefaultHttpClient) requestFactory.getHttpClient(); TrustStrategy acceptingTrustStrategy = (cert, authType) -> true SSLSocketFactory sf = new SSLSocketFactory( acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER); httpClient.getConnectionManager().getSchemeRegistry() .register(new Scheme("https", 8443, sf)); String urlOverHttps = "//localhost:8443/httpclient-simple/api/bars/1"; ResponseEntity response = new RestTemplate(requestFactory). exchange(urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }

Wie Sie sehen, ist dies der Art und Weise, wie wir SSL für den unformatierten HttpClient konfiguriert haben , sehr ähnlich. Wir konfigurieren die Anforderungsfactory mit SSL-Unterstützung und instanziieren dann die Vorlage, die diese vorkonfigurierte Factory übergibt.

6. Das Spring RestTemplate mit SSL (HttpClient 4.4)

Und wir können unser RestTemplate auf dieselbe Weise konfigurieren :

@Test public void givenAcceptingAllCertificatesUsing4_4_whenUsingRestTemplate_thenCorrect() throws ClientProtocolException, IOException { CloseableHttpClient httpClient = HttpClients.custom() .setSSLHostnameVerifier(new NoopHostnameVerifier()) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); ResponseEntity response = new RestTemplate(requestFactory).exchange( urlOverHttps, HttpMethod.GET, null, String.class); assertThat(response.getStatusCode().value(), equalTo(200)); }

7. Fazit

In diesem Lernprogramm wurde erläutert, wie Sie SSL für einen Apache HttpClient so konfigurieren, dass er unabhängig vom Zertifikat jede HTTPS-URL verwenden kann. Die gleiche Konfiguration für das Spring RestTemplate ist ebenfalls dargestellt.

Es ist jedoch wichtig zu verstehen, dass diese Strategie die Zertifikatsprüfung vollständig ignoriert - was sie unsicher macht und nur dort verwendet werden kann, wo dies sinnvoll ist.

Die Implementierung dieser Beispiele finden Sie im GitHub-Projekt - dies ist ein Eclipse-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.