java - SSL 握手警报 : unrecognized_name error since upgrade to Java 1. 7.0

标签 java ssl

我今天从 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实现后备设置。

关于java - SSL 握手警报 : unrecognized_name error since upgrade to Java 1. 7.0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7615645/

相关文章:

java - 在 Java 中验证整数值的问题

java - 以下语句中的大括号是否表示开数组?

java - 为什么在java中接口(interface)中的静态最终变量可以被本地变量覆盖?

c - X509 结构的正确释放在链和主证书添加之间是否有所不同?

ssl - 在 Rust 中使用 async-tls 进行 tls 握手的未知发行者

perl - 你如何验证服务器证书和链中的每个证书直到 perl 中的 ROOT - 4 级深

java - 如何确定 web.xml 中监听器的顺序

java - 导入错误 : Org. Hibernate.SessionFactory 等

perl - IO::Socket::SSL 似乎忽略了 SSL_VERIFY_NONE

ruby-on-rails - Heroku 控制台中的预期 (200) <=> 实际 (401 未经授权)