JAVA 6 不支持 SNI,还有其他方法可以通过 TLS 验证和接受 SSL 证书吗?

JAVA 6 does not support SNI, Any Alternative way to verify and accept SSL Certificate over TLS?

我知道浏览器和 java7 不受影响的原因是因为它们发送服务器名称指示-SNI 作为 SSL 信息的一部分。因此,apache 在开始 SSL 握手和 returns 正确的证书之前知道要使用哪个虚拟主机。 Java 6 不支持 SNI。所以我的问题是,如何验证并允许证书在 java 6.

中被接受

我制作了一个 spring 客户端来使用网络服务,这是我的代码

public class classname1 {

    static {
        System.setProperty("javax.net.ssl.trustStore", "E://Workspace//keystore");
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        System.setProperty("https.protocols", "SSLv3");
        System.setProperty("https.protocols", "TLSv1");

    }
    static {

                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
                    {
                        public boolean verify(String hostname, SSLSession session)
                        {
                            if (hostname.equals("192.168.10.22"))
                                return true;
                            return false;
                        }
                    });
            }

    private static void main(String[] args) {
        try {
            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();

            String url = "https://192.168.10.22/getInformationSearch.asmx?wsdl";
            SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url);
            printSOAPResponse(soapResponse);
            soapConnection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static SOAPMessage createSOAPRequest() throws Exception {
        // ... Code for request, which will be hitted to url
    }

    private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception {
        // ... Code for response, which will fetch information from webservice
        // URL
    }

}

如您所见,我创建了两种方法,1. 用于请求 createSOAPRequest() 2. 用于响应 printSOAPResponse()。 (Url 上面代码段中的名称已更改)

main()方法中,下面的行将生成请求并将该请求发送给给定的url SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url);,然后它进入静态块,如上HttpsURLConnection.setDefaultHostnameVerifier()方法所示。

当时,调试器说:ssl 握手失败,SSL 对等端错误关闭。它仅在 JAVA 6 中发生,但这些代码在 java 7/8 中正常工作。

我在 java 6

中尝试了以下代码,而不是那个静态块
 HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName,
                        SSLSession session) {
                    return true;
                }
            };

但无论如何都行不通!!!

我正在使用以下 jar xercesImpl.jar,saaj-api.jar,saaj-impl.jar,spring-ws-core-1.5.6.jar, spring-ws-security-1.5.6.jar 并且此 SSL 域的证书已导入到密钥库中并且在 java7/8 中有效,因此信任库中没有问题,对吧? (我也使用 java 6 和 7 的密钥工具制作了 2 个证书,两者在 java7/8 中都可以正常工作,但在 6 中则不行)

我遵循了这个 thread 但它不起作用。那么有没有其他方法可以在 java 6 环境中验证证书并获得响应,或者我应该更改任何 JAR 吗?

正如您已经提到的Java 6 不支持 SNI。但是,缺少 SNI 的问题不仅在于验证证书(因为服务器发送了错误的证书),而且根据服务器配置,如果 SNI 扩展不存在且未指向,服务器将导致握手错误服务器上可用的主机名。这显然是这里的情况:

... ssl handshake failed and SSL peer shut down incorrectly. It happens only in JAVA 6 but these code working proper with java 7/8.

在这种情况下,尝试像您尝试的那样更改证书的验证根本无济于事,因为错误发生在客户端甚至没有要验证的证书之前。这意味着没有办法绕过它:如果你想与这个特定的服务器通信,你需要在你的客户端中支持 SNI。

如果服务器未配置为允许您在没有 SNI 的情况下进行连接,则不能。

如果没有 SNI,在建立 SSL 连接 之前,服务器无法判断您想要哪个虚拟主机。

要查看差异,如果您有 OpenSSL,则可以使用 the s_client option 来提取所提供的不同证书,或者当您不使用 SNI 时可能会注意到连接失败:

SNI:

echo | openssl s_client -servername www.virtualhost.com -connect 192.168.1.55:443 | openssl x509 -text

192.168.1.55替换为服务器的实际IP地址,将www.virtualhost.com替换为您要连接的虚拟主机的主机名。管道前面的 echo 命令可防止 openssl 在等待输入时挂起。

没有 SNI:

echo | openssl s_client -connect 192.168.1.55:443 | openssl x509 -text

如果没有 SNI,您可能会看到一个完全不同的证书,或者您可能会遇到连接错误。