HttpClient dengan SSL

1. Gambaran keseluruhan

Artikel ini akan menunjukkan cara mengkonfigurasi Apache HttpClient 4 dengan sokongan SSL "Terima Semua" . Tujuannya adalah mudah - gunakan URL HTTPS yang tidak mempunyai sijil yang sah.

Sekiranya anda ingin menggali lebih mendalam dan mengetahui perkara menarik lain yang boleh anda lakukan dengan HttpClient - terus ke panduan utama HttpClient .

2. Pengecualian SSLPeerUnverifiedException

Tanpa mengkonfigurasi SSL dengan HttpClient , ujian 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 yang tepat 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 berlaku apabila rantaian yang sah amanah tidak boleh ditubuhkan untuk URL.

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

Sekarang, konfigurasikan klien HTTP untuk mempercayai semua rantai sijil tanpa mengira kesahihannya:

@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 kini mengesampingkan proses pengesahan sijil standard (yang harus berunding dengan pengurus kepercayaan yang dikonfigurasikan) - ujian kini lulus dan pelanggan dapat menggunakan URL HTTPS .

4. Konfigurasikan SSL - Terima Semua (HttpClient 4.4 dan Ke Atas)

Dengan HTTPClient baru, sekarang kami mempunyai pengesahan nama host SSL lalai yang disempurnakan dan direka bentuk semula. Juga dengan pengenalan SSLConnectionSocketFactory dan RegistryBuilder , mudah untuk membina SSLSocketFactory. Oleh itu, kita boleh menulis kes ujian 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. Spring RestTemplate dengan SSL (HttpClient <4.3)

Sekarang kita telah melihat bagaimana mengkonfigurasi HttpClient mentah dengan sokongan SSL, mari kita lihat pelanggan tahap lebih tinggi - Spring RestTemplate .

Tanpa SSL dikonfigurasi, ujian 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)); }

Oleh itu, mari 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 mengkonfigurasi SSL untuk HttpClient mentah - kami mengkonfigurasi kilang permintaan dengan sokongan SSL dan kemudian kami membuat templat yang melewati kilang yang telah dikonfigurasikan ini.

6. Spring RestTemplate dengan SSL (HttpClient 4.4)

Dan kita boleh menggunakan cara yang sama untuk mengkonfigurasi RestTemplate kami :

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

Tutorial ini membincangkan bagaimana mengkonfigurasi SSL untuk Apache HttpClient sehingga dapat menggunakan URL HTTPS apa pun, tanpa mengira sijilnya. Konfigurasi yang sama untuk Spring RestTemplate juga digambarkan.

Yang penting untuk difahami adalah strategi ini sepenuhnya mengabaikan pemeriksaan sijil - yang menjadikannya tidak selamat dan hanya digunakan di mana yang masuk akal.

Pelaksanaan contoh-contoh ini boleh didapati di projek GitHub - ini adalah projek berasaskan Eclipse, jadi mudah untuk diimport dan dijalankan sebagaimana adanya.