如何使用Apache HTTPComponents HttpClient在HTTP请求中启用SNI?

时间:2014-09-15 18:31:59

标签: apache-httpclient-4.x sni

我试图弄清楚如何将成功的HTTP GET请求发送到需要SNI的服务器。

我搜索了SO和其他地方,发现一些文章说JDK现在支持SNI,以及Apache HTTP Components。

https://issues.apache.org/jira/browse/HTTPCLIENT-1119 https://wiki.apache.org/HttpComponents/SNISupport

相关SO文章:Certificate chain different between HTTPSURLconnection and Apache (System) DefaultHttpClient

-

但是,我似乎无法找到任何显示如何使其发挥作用的文档。

以下是我正在使用的代码......


            KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
            String trustedCertsPath = System.getenv("JAVA_HOME") + "/jre/lib/security/cacerts";
            FileInputStream certstream = new FileInputStream(new File(trustedCertsPath));
            try {
                trustStore.load(certstream, "changeit".toCharArray());
            } finally {
                certstream.close();
            }

// Trust own CA and all self-signed certs SSLContext sslcontext = SSLContexts.custom() .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build(); // Allow TLSv1 protocol only SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); CloseableHttpClient httpclient2 = HttpClients.custom() .setSSLSocketFactory(sslsf) .build(); CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget = new HttpGet(uri); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); if (entity != null) { tempFile = File.createTempFile(httpFile.getTempFilePrefix(), httpFile.getTempFilePosfix()); FileOutputStream os = new FileOutputStream(tempFile); InputStream instream = entity.getContent(); try { IOUtils.copy(instream, os); } finally { try { instream.close(); } catch (Exception e) {} try { os.close(); } catch (Exception e) {} } } } finally { response.close(); }

当我运行此命令时,请求失败。

服务器在请求中需要SNI,如果没有它,它将返回一个具有错误CommonName的过期证书,因为它被拒绝。

如果我使用httpclient2实例,即使用自定义SSL上下文设置以允许所有hTTP证书,则请求成功。但是,这不是我想要在每天针对不同主机进行大量下载的服务器上启用的。

我正在使用httpclient v 4.3.5

任何帮助表示感谢。

感谢。

1 个答案:

答案 0 :(得分:8)

在Java 1.7或更高版本上运行时,SNI应该完全透明地工作。无需配置。如果无论出于何种原因SSL启用服务器的SSL握手失败,您应该能够通过打开SSL调试日志来找出原因(以及是否正确使用SNI扩展),如此处所述[1]和此处[2]

'调试SSL / TLS连接'可能看起来过时,但在解决SSL相关问题时仍然有用。

[1] http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html

[2] http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#Debug