SSL 握手警报:升级到 Java 1.7.0 后出现 unrecognized_name 错误 [英] SSL handshake alert: unrecognized_name error since upgrade to Java 1.7.0

查看:45
本文介绍了SSL 握手警报:升级到 Java 1.7.0 后出现 unrecognized_name 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I upgraded from Java 1.6 to Java 1.7 today. Since then an error occur when I try to establish a connection to my webserver over 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);  
}

这只是一个测试项目,这就是为什么我允许并使用不受信任的证书与代码:

Its only a test project thats why I allow and use untrusted certificates with the code:

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.我的错在哪里?

I sucessfully tried to connect to https://google.com. where is my fault?

谢谢.

推荐答案

Java 7 引入了默认启用的 SNI 支持.我发现某些配置错误的服务器在 SSL 握手中发送了无法识别的名称"警告,大多数客户端都忽略了该警告...... Java 除外.正如 @Bob Kerns 所述,Oracle 工程师拒绝修复"此错误/功能.

Java 7 introduced SNI support which is enabled by default. I have found out that certain misconfigured servers send an "Unrecognized Name" warning in the SSL handshake which is ignored by most clients... except for Java. As @Bob Kerns mentioned, the Oracle engineers refuse to "fix" this bug/feature.

作为解决方法,他们建议设置 jsse.enableSNIExtension 属性.要让您的程序无需重新编译即可运行,请按以下方式运行您的应用:

As workaround, they suggest to set the jsse.enableSNIExtension property. To allow your programs to work without re-compiling, run your app as:

java -Djsse.enableSNIExtension=false yourClass

该属性也可以在 Java 代码中设置,但必须在任何 SSL 操作之前设置.一旦加载了 SSL 库,您就可以更改该属性,但它 不会对 SNI 状态有任何影响.要在运行时禁用 SNI(具有上述限制),请使用:

The property can also be set in the Java code, but it must be set before any SSL actions. Once the SSL library has loaded, you can change the property, but it won't have any effect on the SNI status. To disable SNI on runtime (with the aforementioned limitations), use:

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

设置这个标志的缺点是在应用程序的任何地方都禁用了 SNI.为了利用 SNI 并仍然支持错误配置的服务器:

The disadvantage of setting this flag is that SNI is disabled everywhere in the application. In order to make use of SNI and still support misconfigured servers:

  1. 使用您要连接的主机名创建一个 SSLSocket.让我们将此命名为 sslsock.
  2. 尝试运行 sslsock.startHandshake().这将阻塞直到它完成或在错误时抛出异常.每当 startHandshake() 发生错误时,获取异常消息.如果它等于 handshake alert: unrecognized_name,那么你发现了一个错误配置的服务器.
  3. 当您收到 unrecognized_name 警告(在 Java 中是致命的)时,重试打开一个 SSLSocket,但这次没有主机名.这有效地禁用了 SNI(毕竟,SNI 扩展是关于向 ClientHello 消息添加主机名).
  1. Create a SSLSocket with the host name you want to connect to. Let's name this sslsock.
  2. Try to run sslsock.startHandshake(). This will block until it is done or throw an exception on error. Whenever an error occurred in startHandshake(), get the exception message. If it equals to handshake alert: unrecognized_name, then you have found a misconfigured server.
  3. When you have received the unrecognized_name warning (fatal in Java), retry opening a SSLSocket, but this time without a host name. This effectively disables SNI (after all, the SNI extension is about adding a host name to the ClientHello message).

对于 Webscarab SSL 代理,此提交实现了回退设置.

For the Webscarab SSL proxy, this commit implements the fall-back setup.

这篇关于SSL 握手警报:升级到 Java 1.7.0 后出现 unrecognized_name 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆