1. 程式人生 > >[譯]HttpClient請求HTTPS URL

[譯]HttpClient請求HTTPS URL

.exe med end set cookie ger true rate cti

1.概覽

本文將演示如何配置Apache HttpClient 4 添加ssl支持.目的很簡單----無需有效證書即可成功請求 HTTPS URLs.

如果你想深入挖掘和學習其他和HttpClient相關的酷知識,請點擊httpclient-guide

延伸閱讀:

httpclient-connection-management

httpclient-advanced-config

httpclient-4-cookies

2. SSLPeerUnverifiedException異常

使用httpclient若未配置SSL,下面的測試----請求一個HTTPS URL----將會失敗:

 1
public class HttpLiveTest { 2 3 @Test(expected = SSLPeerUnverifiedException.class) 4 public void whenHttpsUrlIsConsumed_thenException() 5 throws ClientProtocolException, IOException { 6 7 DefaultHttpClient httpClient = new DefaultHttpClient(); 8 String urlOverHttps
9 = "https://localhost:8080/spring-security-rest-basic-auth"; 10 HttpGet getMethod = new HttpGet(urlOverHttps); 11 12 HttpResponse response = httpClient.execute(getMethod); 13 assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); 14 } 15 }

具體的異常是:

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

不管何時,URL不能建立一個信任的有效鏈時,都會出現javax.net.ssl.SSLPeerUnverifiedException exception異常.

3.配置SSL--Accept All(HttpClient的版本小於4.3)

下面通過配置HTTP client信任所有鏈(譯者註:chains)無論他們是否有效.

 1 @Test
 2 public void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenException() 
 3   throws IOException, GeneralSecurityException {
 4     TrustStrategy acceptingTrustStrategy = (cert, authType) -> true;
 5     SSLSocketFactory sf = new SSLSocketFactory(
 6       acceptingTrustStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
 7     SchemeRegistry registry = new SchemeRegistry();
 8     registry.register(new Scheme("https", 8443, sf));
 9     ClientConnectionManager ccm = new PoolingClientConnectionManager(registry);
10  
11     DefaultHttpClient httpClient = new DefaultHttpClient(ccm);
12  
13     String urlOverHttps 
14       = "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1";
15     HttpGet getMethod = new HttpGet(urlOverHttps);
16      
17     HttpResponse response = httpClient.execute(getMethod);
18     assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
19 }

在新的信任策略下,覆蓋了原有的標準證書驗證過程(原本需要咨詢一個配置好的信任管理器)----上面的測試通過則表明現在的client可以請求HTTPS URL了.

4.spring的RestTemplate配置SSL(HttpClient的版本小於4.3)

我們已經知曉如何給原生的HttpClient配置添加SSL支持,再看看一下更高級的client----the Spring RestTemplate.

沒有配置SSL的情況下,如預期一致,下面的測試將不會通過:

1 @Test(expected = ResourceAccessException.class)
2 public void whenHttpsUrlIsConsumed_thenException() {
3     String urlOverHttps 
4       = "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1";
5     ResponseEntity<String> response 
6       = new RestTemplate().exchange(urlOverHttps, HttpMethod.GET, null, String.class);
7     assertThat(response.getStatusCode().value(), equalTo(200));
8 }

下面配置SSL:

 1 import static org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
 2 import java.security.GeneralSecurityException;
 3 import java.security.cert.X509Certificate;
 4 import org.apache.http.auth.AuthScope;
 5 import org.apache.http.auth.UsernamePasswordCredentials;
 6 import org.apache.http.conn.scheme.Scheme;
 7 import org.apache.http.conn.ssl.SSLSocketFactory;
 8 import org.apache.http.conn.ssl.TrustStrategy;
 9 import org.apache.http.impl.client.DefaultHttpClient;
10 import org.springframework.http.HttpMethod;
11 import org.springframework.http.ResponseEntity;
12 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
13 import org.springframework.web.client.ResourceAccessException;
14 import org.springframework.web.client.RestTemplate;
15  
16 ...
17 @Test
18 public void givenAcceptingAllCertificates_whenHttpsUrlIsConsumed_thenException() 
19   throws GeneralSecurityException {
20     HttpComponentsClientHttpRequestFactory requestFactory 
21       = new HttpComponentsClientHttpRequestFactory();
22     DefaultHttpClient httpClient
23       = (DefaultHttpClient) requestFactory.getHttpClient();
24     TrustStrategy acceptingTrustStrategy = (cert, authType) -> true
25     SSLSocketFactory sf = new SSLSocketFactory(
26       acceptingTrustStrategy, ALLOW_ALL_HOSTNAME_VERIFIER);
27     httpClient.getConnectionManager().getSchemeRegistry()
28       .register(new Scheme("https", 8443, sf));
29  
30     String urlOverHttps
31       = "https://localhost:8443/spring-security-rest-basic-auth/api/bars/1";
32     ResponseEntity<String> response = new RestTemplate(requestFactory).
33       exchange(urlOverHttps, HttpMethod.GET, null, String.class);
34     assertThat(response.getStatusCode().value(), equalTo(200));
35 }

正如你所見,這和原生的HttpClient配置SSL非常相像----我們給 request factory 添加了SSL支持,然後初始化模板時將配置好的factory作為入參.

5.配置SSL(HttpClient版本為4.4)

在4.4版本,不再使用SSLSocketFactory,可簡單配置如下:

 1 @Test
 2 public void givenIgnoringCertificates_whenHttpsUrlIsConsumed_thenCorrect()
 3   throws Exception {
 4     SSLContext sslContext = new SSLContextBuilder()
 5       .loadTrustMaterial(null, (certificate, authType) -> true).build();
 6  
 7     CloseableHttpClient client = HttpClients.custom()
 8       .setSSLContext(sslContext)
 9       .setSSLHostnameVerifier(new NoopHostnameVerifier())
10       .build();
11     HttpGet httpGet = new HttpGet(HOST_WITH_SSL);
12     httpGet.setHeader("Accept", "application/xml");
13  
14     HttpResponse response = client.execute(httpGet);
15     assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
16 }

6.Spring RestTemplate 配置 SSL (HttpClient 4.4)

我們可以使用同樣的方式配置RestTemplate :

 1 @Test
 2 public void givenAcceptingAllCertificatesUsing4_4_whenUsingRestTemplate_thenCorrect() 
 3 throws ClientProtocolException, IOException {
 4     CloseableHttpClient httpClient
 5       = HttpClients.custom()
 6         .setSSLHostnameVerifier(new NoopHostnameVerifier())
 7         .build();
 8     HttpComponentsClientHttpRequestFactory requestFactory 
 9       = new HttpComponentsClientHttpRequestFactory();
10     requestFactory.setHttpClient(httpClient);
11  
12     ResponseEntity<String> response 
13       = new RestTemplate(requestFactory).exchange(
14       urlOverHttps, HttpMethod.GET, null, String.class);
15     assertThat(response.getStatusCode().value(), equalTo(200));
16 }

7.總結

本教程討論了如何給 Apache HttpClient 配置SSL ,忽略校驗以至於能夠訪問任何 HTTPS URL .並舉例說明給Spring RestTemplate配置SSL.

然而需要明白的是:該策略完全忽略證書驗證,這可能導致安全漏洞,因此只能用在需要的地方.

本文的示例代碼可訪問 the GitHub project ,工程基於Eclipse,因此可以輕松導入並運行.

8.原文地址:

傳送門

[譯]HttpClient請求HTTPS URL