HttpClient dengan SSL

1. Ikhtisar

Artikel ini akan menunjukkan cara mengkonfigurasi Apache HttpClient 4 dengan dukungan SSL "Terima Semua" . Tujuannya sederhana - gunakan URL HTTPS yang tidak memiliki sertifikat yang valid.

Jika Anda ingin menggali lebih dalam dan mempelajari hal-hal keren lainnya yang dapat Anda lakukan dengan HttpClient - lanjutkan ke panduan HttpClient utama .

2. SSLPeerUnverifiedException

Tanpa mengonfigurasi SSL dengan HttpClient , pengujian berikut - menggunakan URL HTTPS - akan gagal:

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

Kegagalan tepatnya adalah:

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

The javax.net.ssl.SSLPeerUnverifiedException pengecualian terjadi setiap kali rantai valid kepercayaan tidak dapat ditentukan untuk URL.

3. Konfigurasi SSL - Terima Semua (HttpClient <4.3)

Sekarang mari kita konfigurasikan klien HTTP untuk mempercayai semua rantai sertifikat terlepas dari validitasnya:

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

Dengan TrustStrategy baru yang sekarang menggantikan proses verifikasi sertifikat standar (yang seharusnya berkonsultasi dengan pengelola kepercayaan yang dikonfigurasi) - pengujian sekarang berhasil dan klien dapat menggunakan URL HTTPS .

4. Konfigurasi SSL - Terima Semua (HttpClient 4.4 dan Lebih Tinggi)

Dengan HTTPClient baru, sekarang kami memiliki pemverifikasi nama host SSL default yang telah didesain ulang dan disempurnakan. Juga dengan pengenalan SSLConnectionSocketFactory dan RegistryBuilder , mudah untuk membangun SSLSocketFactory. Jadi kita bisa menulis test case di atas seperti:

@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. Template Spring Rest dengan SSL (HttpClient <4.3)

Sekarang kita telah melihat bagaimana mengkonfigurasi HttpClient mentah dengan dukungan SSL, mari kita lihat klien tingkat yang lebih tinggi - Spring RestTemplate .

Tanpa konfigurasi SSL, pengujian berikut gagal seperti yang diharapkan:

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

Jadi mari kita konfigurasikan 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)); }

Seperti yang Anda lihat, ini sangat mirip dengan cara kami mengonfigurasi SSL untuk HttpClient mentah - kami mengonfigurasi pabrik permintaan dengan dukungan SSL dan kemudian kami membuat contoh templat yang melewati pabrik yang telah dikonfigurasi sebelumnya ini.

6. Template Spring Rest dengan SSL (HttpClient 4.4)

Dan kita dapat menggunakan cara yang sama untuk mengkonfigurasi RestTemplate kita :

@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. Kesimpulan

Tutorial ini membahas cara mengonfigurasi SSL untuk Apache HttpClient agar dapat menggunakan URL HTTPS apa pun, apa pun sertifikatnya. Konfigurasi yang sama untuk Spring RestTemplate juga diilustrasikan.

Namun, satu hal penting untuk dipahami adalah bahwa strategi ini sepenuhnya mengabaikan pemeriksaan sertifikat - yang membuatnya tidak aman dan hanya digunakan di tempat yang memungkinkan.

Penerapan contoh-contoh ini dapat ditemukan di proyek GitHub - ini adalah proyek berbasis Eclipse, jadi semestinya mudah untuk mengimpor dan menjalankannya apa adanya.