JAVA 6 不支持 SNI,还有其他方法可以通过 TLS 验证和接受 SSL 证书吗?
Posted
技术标签:
【中文标题】JAVA 6 不支持 SNI,还有其他方法可以通过 TLS 验证和接受 SSL 证书吗?【英文标题】:JAVA 6 does not support SNI, Any Alternative way to verify and accept SSL Certificate over TLS? 【发布时间】:2017-02-17 08:42:13 【问题描述】:我知道浏览器和 java7 不受影响的原因是它们发送服务器名称指示-SNI 作为 SSL 信息的一部分。因此,apache 在开始 SSL 握手之前知道要使用哪个虚拟主机并返回正确的证书。 Java 6 不支持 SNI。所以我的问题是,如何验证并允许在 java 6 中接受证书。
我做了一个spring客户端来消费webservice,这是我的代码
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()
。 (上面sn-p中的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;
;
但无论如何它都不会工作!!!
我正在使用以下 jars 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 的 keytool 制作了 2 个证书,两者在 java7/8 中都可以正常工作,但在 6 中则不行)
我关注了这个thread,但它不起作用。那么有没有其他方法可以在 java 6 环境中验证证书并获得响应,或者我应该更改任何 JAR 吗?
【问题讨论】:
【参考方案1】:正如您已经提到的,Java 6 不支持 SNI。但是,缺少 SNI 的问题不仅在于验证证书(因为服务器发送了错误的证书),而且取决于服务器配置,如果 SNI 扩展不存在且不指向服务器,则服务器将导致握手错误服务器上可用的主机名。这显然是这里的情况:
... ssl 握手失败,SSL 对等点错误关闭。它只发生在 JAVA 6 中,但这些代码在 java 7/8 中正常工作。
在这种情况下,尝试更改证书的验证将完全没有帮助,因为错误发生在客户端甚至没有要验证的证书之前。这意味着没有办法绕过它:如果你想与这个特定的服务器通信,你需要在你的客户端中支持 SNI。
【讨论】:
【参考方案2】:如果服务器未配置为允许您在没有 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,您可能会看到完全不同的证书,或者您可能会遇到连接错误。
【讨论】:
以上是关于JAVA 6 不支持 SNI,还有其他方法可以通过 TLS 验证和接受 SSL 证书吗?的主要内容,如果未能解决你的问题,请参考以下文章
使用 SNI 和 Undertow 在一个 IP 下添加多个域