SSL握手警报:升级到Java 1.7.0后,无法识别的名称错误

问题:

我今天从Java 1.6升级到Java 1.7。
此后,当我尝试通过SSL建立与我的网络服务器的连接时,会发生错误:

javax.net.ssl.SSLProtocolException: handshake alert:  unrecognized_name
    at sun.security.ssl.ClientHandshaker.handshakeAlert(ClientHandshaker.java:1288)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1904)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1027)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1262)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1289)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1273)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at java.net.URL.openStream(URL.java:1035)

这是代码:

SAXBuilder builder = new SAXBuilder();
Document document = null;

try {
    url = new URL(https://some url);
    document = (Document) builder.build(url.openStream());
} catch (NoSuchAlgorithmException ex) {
    Logger.getLogger(DownloadLoadiciousComputer.class.getName()).log(Level.SEVERE, null, ex);  
}

它只是一个测试项目,为什么我允许和使用不可信证书与代码:

TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {

        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

try {

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {

    Logger.getLogger(DownloadManager.class.getName()).log(Level.SEVERE, null, e);
} 

我成功尝试连接到https://google.com
我的错在哪里?
谢谢。

回答:

Java 7引入了默认启用的SNI支持。我发现某些配置错误的服务器在SSL握手中发送了一个“无法识别的名称”警告,这被大多数客户端忽略,除了Java。正如@Bob Kerns所述,Oracle工程师拒绝“修复”这个错误/功能。
作为解决方法,他们建议设置jsse.enableSNIExtension属性。为了让您的程序在没有重新编译的情况下运行,请运行您的应用程序:

java -Djsse.enableSNIExtension=false yourClass

该属性也可以在Java代码中设置,但必须设置为在任何SSL操作之前。加载SSL库后,您可以更改属性,但是won’t have any effect on the SNI status。要在运行时禁用SNI(具有上述限制),请使用:

System.setProperty("jsse.enableSNIExtension", "false");

设置此标志的缺点是SNI在应用程序中无处不在。为了利用SNI并仍然支持配置错误的服务器:

  1. 使用要连接的主机名创建一个SSLSocket。我们来命名这个sslsock
  2. 尝试运行sslsock.startHandshake()。这将阻止,直到它完成或抛出异常错误。无论何时startHandshake()发生错误,请获取异常消息。如果它等于handshake alert: unrecognized_name,那么您发现配置错误的服务器。
  3. 当您收到unrecognized_name警告(在Java中致命)时,重试打开SSLSocket,但这次没有主机名。这有效地禁用SNI(毕竟,SNI扩展是关于向ClientHello消息添加主机名)。

对于Webscarab SSL代理,this commit实现了后退设置。

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: SSL handshake alert: unrecognized_name error since upgrade to Java 1.7.0

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

+ 15 = 18