我今天从Java 1.6升级到Java 1.7。 从那时起,当我试图通过SSL建立连接到我的web服务器时,出现了一个错误:

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 1.6_29升级到1.7时,我也遇到过这个问题。

令人震惊的是,我的客户在Java控制面板中发现了一个可以解决这个问题的设置。

在高级选项卡中,你可以勾选“使用兼容SSL 2.0的ClientHello格式”。

这似乎解决了问题。

我们在Internet Explorer浏览器中使用Java小程序。

希望这能有所帮助。

其他回答

在这里加上一个解。这可能对LAMP用户有所帮助

Options +FollowSymLinks -SymLinksIfOwnerMatch

虚拟主机配置中的上述行是罪魁祸首。

虚拟主机配置错误时

<VirtualHost *:80>
    DocumentRoot /var/www/html/load/web
    ServerName dev.load.com
    <Directory "/var/www/html/load/web">
        Options +FollowSymLinks -SymLinksIfOwnerMatch
        AllowOverride All
        Require all granted
        Order Allow,Deny
        Allow from All
    </Directory>
     RewriteEngine on
     RewriteCond %{SERVER_PORT} !^443$
     RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
</VirtualHost>

配置工作

<VirtualHost *:80>
    DocumentRoot /var/www/html/load/web

   ServerName dev.load.com
   <Directory "/var/www/html/load/web">

        AllowOverride All

        Options All

        Order Allow,Deny

        Allow from All

    </Directory>

    # To allow authorization header
    RewriteEngine On
    RewriteCond %{HTTP:Authorization} ^(.*)
    RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

   # RewriteCond %{SERVER_PORT} !^443$
   # RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]


</VirtualHost>

我遇到了同样的问题,原来反向dns设置不正确,它指向错误的IP主机名。在我纠正反向dns并重新启动httpd后,警告消失了。 (如果我不纠正反向dns,添加ServerName也为我做了技巧)

Java 7引入了默认启用的SNI支持。我发现某些错误配置的服务器在SSL握手中发送一个“无法识别的名称”警告,大多数客户端都会忽略这个警告…除了Java。正如bob Kerns提到的,Oracle工程师拒绝“修复”这个bug/特性。

作为解决方案,他们建议设置jsse。enableSNIExtension财产。为了让你的程序在不重新编译的情况下工作,运行你的应用程序:

java -Djsse.enableSNIExtension=false yourClass

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

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

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

Create a SSLSocket with the host name you want to connect to. Let's name this sslsock. 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. 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代理,此提交实现了回退设置。

在spring引导和jvm 1.7和1.8时遇到了这个问题。在AWS上,我们没有选项来更改serververname和ServerAlias来匹配(它们是不同的),所以我们做了以下工作:

在构建。Gradle我们添加了以下内容:

System.setProperty("jsse.enableSNIExtension", "false")
bootRun.systemProperties = System.properties

这让我们绕过了“无法识别的名字”的问题。

而不是依赖apache中的默认虚拟主机机制,您可以定义最后一个使用任意ServerName和通配符ServerAlias的catchall虚拟主机,例如:

ServerName catchall.mydomain.com
ServerAlias *.mydomain.com

这样你就可以使用SNI, apache不会返回SSL警告。

当然,这只有在您可以使用通配符语法轻松描述所有域的情况下才有效。