Java上的服务器名称指示(SNI)



有人能帮我开始用Java进行带有服务器名称指示的HTTP连接吗?

我正在尝试从我管理的网站请求内容。我一直在使用Apache的HttpClient库,但我对安全内容的请求失败了,因为该网站只使用HTTPS的SNI,并且在DefaultHttpClient中没有启用SNI。我已经在Apache的HttpClient库中寻找了如何处理这一问题的指导,但我看到了以下文档:http://hc.apache.org/httpclient-3.x/sslguide.html,这已经过时了(指的是HttpClient和HttpCore是Apache的commons包的一部分时的代码)。

所以。。。有什么帮助吗?

您可能想要跟踪https://issues.apache.org/jira/browse/HTTPCLIENT-1119

Java 7的底层客户端实现能够支持它,并通过SSLSocketImpl#setHost(由sun.netwww.protocol.https.HttpsClient 调用

在Java 7上使用

    new URL("https://cmbntr.sni.velox.ch/").openStream()

直到HTTPCLIENT-1119固定

这就是我在org.apache.httpcomponents的httpclient v4.3+中所做的

private HttpClientConnectionManager createConnectionManager(final SSLContext ctx) {
    LOG.info("Creating sslConnectionSocketFactory");
    final SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(ctx) {
        @Override
        protected void prepareSocket(SSLSocket socket) throws IOException {
            try {
                System.out.println("************ setting socket HOST property *************");
                PropertyUtils.setProperty(socket, HOST, Constants.SNI_HOST);
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
                LOG.error(ex.getMessage());
            }
            super.prepareSocket(socket); 
        }
    };
    LOG.info("Creating connectionRegistry");
    final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("https", sslSF)
            .build();
    LOG.info("Creating poolingConnectionManager");
    final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
    connectionManager.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE);
    connectionManager.setMaxTotal(MAX_CONNECTIONS);
    return connectionManager;
}

这就是我创建HttpClient 的方式

final KeyManager[] keyManagers = createKeyManagers();
final TrustManager[] trustManagers = createTrustManagers();
final SSLContext ctx = createSslContext(keyManagers, trustManagers);
final HttpClientConnectionManager connectionManager = createConnectionManager(ctx);
LOG.info("Creating httpClient");
HttpClient httpClient = HttpClients
        .custom()
        .setConnectionManager(connectionManager)
        .build();

使用一个简短的修复程序,如下所述:Java客户端中带SNI的TLS可以将SNI服务器支持添加到JDK7中,并将其与X509ExtendedKeyManager一起使用。

对我有效的是在Apache配置中正确配置ServerName

/etc/apache2/sites-avaible/default

<VirtualHost *:443>
  ServerName foo.domain.com
  ...
</VirtualHost>

如中所述https://stackoverflow.com/a/8058839/2088282.

这个问题似乎在Java 7中得到了修复。

最新更新