[译]HttpClient请求HTTPS URL

Posted wangliangwu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[译]HttpClient请求HTTPS URL相关的知识,希望对你有一定的参考价值。

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的主要内容,如果未能解决你的问题,请参考以下文章

JAVA利用HttpClient进行POST请求(HTTPS)

带有“@”的 HttpClient 访问 url(在符号处)

php的httpclient怎么请求https

java——HttpClient 代理模式发送Http Https(未完成,没贴代码呢)

HttpClient基本使用

HttpClient POST/SET方法