如何使用 TLSv1.2 在 Apache HttpClient 中忽略 "localhost"?

How to ignore "localhost" in Apache HttpClient using TLSv1.2?

我测试了 Apache HttpClinet(HTTPS 和 TLS)的几种语法结构,以便忽略通常在 "localhost" 配置中使用的自签名证书的证书链。有一个适用于 TLSv1.1 的自定义 HttpClient,但观察服务器跟踪,它不会触发使用 TLSv1.2,这是所需的安全算法。

下面是使用 TLSv1.2 配置 HttpClient 的尝试。

欢迎提出其他结构的建议。 "localhost" 场景仍然是开发点对点例程的常用机制。最好有一个可配置的例程,该例程只接受本地主机访问的自签名证书。

TLSv1.1 示例和使用自定义 HttpClient(适用于 TLSv1.1 但不适用于 TLSv1.2):

HttpClient client = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).setSslcontext(new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build()).build();

服务器日志:

*** Finished
verify_data:  { 251, 245, 220, 174, 235, 125, 248, 119, 220, 80, 38, 1 }
***
Thread-7, WRITE: TLSv1 Handshake, length = 48
%% Cached server session: [Session-23, SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA]
Thread-7, WRITE: TLSv1 Application Data, length = 108
Thread-7, WRITE: TLSv1 Application Data, length = 1
Thread-7, WRITE: TLSv1 Application Data, length = 19

客户端 - 正常

Debug HTTP response: HttpResponseProxy{HTTP/1.1 200 OK [Date: Tue, 21 Feb 2017 21:16:02 GMT, Access-control-allow-origin: *, Content-length: 20] ResponseEntityProxy{[Content-Length: 20,Chunked: false]}}
*** end of debug ***
Service HTTP Response Code : 200
contentLength is: 20
serviceResponse : This is the response

使用 TLSv1.2 和代码进行测试

  SSLContext sslContext = SSLContexts.custom().build();
     SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
          new String[]{"TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
     HttpClient client = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).setConnectionManager(clientConnectionManager).build();

(*) SSLContext class 已弃用

服务器日志:

-Djavax.net.debug=ssl
or 
System.setProperty("javax.net.debug", "ssl");

JsseJCE:  Using MAC HmacSHA256 from provider TBD via init 
MAC:  Using MessageDigest HmacSHA256 from provider IBMJCE version 1.8
*** Finished
verify_data:  { 69, 241, 3, 42, 44, 222, 21, 174, 250, 83, 244, 25 }
***
Thread-7, WRITE: TLSv1.2 Handshake, length = 80
%% Cached server session: [Session-21, SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA256]
Thread-7, READ: TLSv1.2 Alert, length = 64
Thread-7, RECV TLSv1.2 ALERT:  warning, close_notify

客户端错误:

sh ./runit.sh 
javax.net.ssl.SSLPeerUnverifiedException: Host name 'localhost' does not match the certificate subject provided by the peer (CN=My Name, OU=RED, O=RED Brazil, L=MYCITY, ST=SP, C=BR)

以下构造成功地使用本地主机证书与 TLSv1.2 连接:

 // solution for localhost certificates and TLSv1.2
 // copied from: 
 // thanks  

      final SSLConnectionSocketFactory sslsf;
        try {
                sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault(),
                    NoopHostnameVerifier.INSTANCE);
        } catch (NoSuchAlgorithmException e) {
             throw new RuntimeException(e);
        }

      final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
              .register("http", new PlainConnectionSocketFactory())
            .register("https", sslsf)
            .build();

      // HttpClient client; 
      final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
        cm.setMaxTotal(100);
        HttpClient client = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .setConnectionManager(cm)
                .build();
      // end of solution for localhost bypass