中山制作網(wǎng)站的公司西安網(wǎng)站推廣慧創(chuàng)科技
本文將展示如何配置Apache HttpClient 4和5以支持“接受所有”SSL。
目標(biāo)很簡單——訪問沒有有效證書的HTTPS URL。
SSLPeerUnverifiedException
在未配置SSL的情況下,嘗試消費一個HTTPS URL時會遇到以下測試失敗:
@Test
void whenHttpsUrlIsConsumed_thenException() {String urlOverHttps = "https://localhost:8082/httpclient-simple";HttpGet getMethod = new HttpGet(urlOverHttps);assertThrows(SSLPeerUnverifiedException.class, () -> {CloseableHttpClient httpClient = HttpClients.createDefault();HttpResponse response = httpClient.execute(getMethod, new CustomHttpClientResponseHandler());assertThat(response.getCode(), equalTo(200));});
}
具體的失敗信息是:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticatedat sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126)...
當(dāng)無法為URL建立有效的信任鏈時,就會拋出javax.net.ssl.SSLPeerUnverifiedException
異常。
配置SSL - 接受所有(HttpClient 5)
現(xiàn)在讓我們配置HTTP客戶端以信任所有證書鏈,無論其有效性如何:
@Test
void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException, IOException {final HttpGet getMethod = new HttpGet(HOST_WITH_SSL);final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true;final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);final Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslsf).register("http", new PlainConnectionSocketFactory()).build();final BasicHttpClientConnectionManager connectionManager =new BasicHttpClientConnectionManager(socketFactoryRegistry);try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(getMethod, new CustomHttpClientResponseHandler())) {final int statusCode = response.getCode();assertThat(statusCode, equalTo(HttpStatus.SC_OK));}
}
通過新的TrustStrategy
覆蓋標(biāo)準(zhǔn)證書驗證過程后,測試現(xiàn)在可以通過,客戶端能夠成功消費HTTPS URL。
配置SSL - 接受所有(HttpClient 4.5)
對于HttpClient 4.5版本,配置方式類似,但使用了一些不同的API:
@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<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> 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<String> response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class);assertThat(response.getStatusCode().value(), equalTo(200));
}
Spring RestTemplate與SSL(HttpClient 5)
了解了如何配置帶有SSL支持的基本HttpClient之后,我們來看看更高級別的客戶端——Spring RestTemplate
。
在沒有配置SSL的情況下,預(yù)期的測試會失敗:
@Test
void whenHttpsUrlIsConsumed_thenException() {final String urlOverHttps = "https://localhost:8443/httpclient-simple/api/bars/1";assertThrows(ResourceAccessException.class, () -> {final ResponseEntity<String> response = new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class);assertThat(response.getStatusCode().value(), equalTo(200));});
}
接下來,配置SSL來解決這個問題:
@Test
void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenOk() throws GeneralSecurityException {final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true;final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);final Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslsf).register("http", new PlainConnectionSocketFactory()).build();final BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry);final CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();final HttpComponentsClientHttpRequestFactory requestFactory =new HttpComponentsClientHttpRequestFactory(httpClient);final ResponseEntity<String> response = new RestTemplate(requestFactory).exchange(urlOverHttps, HttpMethod.GET, null, String.class);assertThat(response.getStatusCode().value(), equalTo(200));
}
這里配置方式與直接使用HttpClient非常相似,我們用帶有SSL支持的請求工廠配置了RestTemplate
。
結(jié)論
本教程討論了如何配置Apache HttpClient以使其能夠消費任何HTTPS URL,無論證書的有效性如何。
同樣也展示了如何對Spring RestTemplate
進行同樣的配置。
重要的是要理解這種策略完全忽略了證書檢查——這使得它不安全,僅應(yīng)在合理的情況下使用。