我知道浏览器和java7不受影响的原因是因为它们将服务器名称指示-SNI作为SSL信息的一部分发送。因此,apache知道在启动SSL握手之前要使用的虚拟主机并返回正确的证书。 Java 6不支持SNI。所以我的问题是,我如何验证并允许在java 6中接受证书。
我做了一个Spring客户端来使用webservice,这是我的代码
('a', 'has_val', 6)
('a', 'has_val', 0)
('b', 'has_val', 3)
('b', 'has_val', 4)
('c', 'has_val', 9)
('c', 'has_val', 5)
('d', 'has_val', 11)
('d', 'has_val', 6)
正如您所看到的那样,我提出了两种方法,1。对于请求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
}
}
2.对于响应createSOAPRequest()
。 (在上面的代码段中更改了网址名称)
在printSOAPResponse()
方法中,下面的行会生成请求并将该请求发送到给定的main()
,然后转到静态块,如上所示url SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url);
方法。
那时,调试器说:ssl握手失败,SSL对等关闭不正确。它只发生在JAVA 6中,但这些代码适用于java 7/8。
而不是那个静态块,我在java 6中试过了下面的代码
HttpsURLConnection.setDefaultHostnameVerifier()
但它无论如何都无法工作!!!
我正在使用以下jars xercesImpl.jar,saaj-api.jar,saaj-impl.jar,spring-ws-core-1.5.6.jar,spring-ws-security-1.5.6.jar和Certificate for这个SSL域已导入到密钥库中,并且在java7 / 8中工作,所以在truststore中没有问题吧? (我使用java 6和7的keytool制作了2个证书,两者在java7 / 8中都可以正常工作,但在6中没有工作)
我遵循了这个thread,但它不起作用。那么有没有其他方法来验证证书并在java 6环境中获得响应,或者我应该更改任何JAR吗?
答案 0 :(得分:2)
正如您已经提到的,Java 6不支持SNI。但是,缺少SNI的问题不仅在于验证证书(因为服务器发送了错误的证书),而且取决于服务器配置,如果SNI扩展不存在并且未指向服务器将导致握手错误服务器上可用的主机名。这显然就是这种情况:
... ssl握手失败,SSL对等关闭不正确。它只发生在JAVA 6中,但这些代码适用于java 7/8。
在这种情况下,尝试更改证书的验证在这种情况下根本无济于事,因为错误发生在客户端甚至有证书要验证之前。这意味着无法绕过它:如果您想与此特定服务器通信,则需要在客户端支持SNI。
答案 1 :(得分: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,您可能会看到完全不同的证书,或者您可能会收到连接错误。