wake-up-neo.net

SSL-Handshake-Warnung: Fehler nicht erkannter Name seit Aktualisierung auf Java 1.7.0

Ich habe heute ein Upgrade von Java 1.6 auf Java 1.7 durchgeführt ..__ Seitdem tritt ein Fehler auf, wenn ich versuche, eine Verbindung zu meinem Webserver über SSL herzustellen:

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)

Hier ist der Code:

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);  
}

Es ist nur ein Testprojekt, weshalb ich nicht vertrauenswürdige Zertifikate mit dem Code zulasse und verwende:

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);
} 

Ich habe erfolgreich versucht, eine Verbindung zu https://google.com . Herzustellen. Wo liegt meine Schuld?

Vielen Dank.

214
pvomhoff

In Java 7 wurde die SNI-Unterstützung eingeführt, die standardmäßig aktiviert ist. Ich habe herausgefunden, dass bestimmte falsch konfigurierte Server im SSL-Handshake eine Warnung "Unbekannter Name" senden, die von den meisten Clients außer Java ignoriert wird. Wie @ Bob Kerns erwähnt, weigern sich die Oracle-Ingenieure, diesen Fehler/diese Funktion zu "beheben".

Als Problemumgehung wird vorgeschlagen, die Eigenschaft jsse.enableSNIExtension festzulegen. Führen Sie Ihre App wie folgt aus, damit Ihre Programme ohne Neukompilierung funktionieren:

Java -Djsse.enableSNIExtension=false yourClass

Die Eigenschaft kann auch im Code Java festgelegt werden, sie muss jedoch vor allen SSL-Aktionen festgelegt werden. Sobald die SSL-Bibliothek geladen wurde, können Sie die Eigenschaft ändern, aber hat keine Auswirkung auf den SNI-Status . Verwenden Sie zum Deaktivieren von SNI zur Laufzeit (mit den oben genannten Einschränkungen) Folgendes:

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

Das Setzen dieses Flags hat den Nachteil, dass SNI überall in der Anwendung deaktiviert ist. Um SNI zu nutzen und weiterhin falsch konfigurierte Server zu unterstützen:

  1. Erstellen Sie ein SSLSocket mit dem Hostnamen, zu dem Sie eine Verbindung herstellen möchten. Nennen wir dieses sslsock.
  2. Versuchen Sie, sslsock.startHandshake() auszuführen. Dies wird blockiert, bis dies erledigt ist oder eine Ausnahme bei einem Fehler ausgelöst wird. Immer wenn ein Fehler in startHandshake() aufgetreten ist, wird die Ausnahmemeldung angezeigt. Wenn es handshake alert: unrecognized_name entspricht, haben Sie einen falsch konfigurierten Server gefunden.
  3. Wenn Sie die Warnung unrecognized_name erhalten haben (schwerwiegend in Java), versuchen Sie erneut, ein SSLSocket zu öffnen, diesmal jedoch ohne Hostnamen. Dadurch wird SNI effektiv deaktiviert (schließlich wird der ClientHello-Nachricht mit der SNI-Erweiterung ein Hostname hinzugefügt).

Für den Webscarab-SSL-Proxy implementiert diese Festschreibung das Fallback-Setup.

297
Lekensteyn

Ich hatte das, von dem ich glaube, dass es sich um dasselbe Problem handelt ... Ich fand heraus, dass ich die Apache-Konfiguration anpassen musste, um einen Servernamen oder ServerAlias ​​für den Host aufzunehmen.

Dieser Code ist fehlgeschlagen:

public class a {
   public static void main(String [] a) throws Exception {
      Java.net.URLConnection c = new Java.net.URL("https://mydomain.com/").openConnection();
      c.setDoOutput(true);
      c.getOutputStream();
   }
}

Und dieser Code hat funktioniert:

public class a {
   public static void main(String [] a) throws Exception {
      Java.net.URLConnection c = new Java.net.URL("https://google.com/").openConnection();
      c.setDoOutput(true);
      c.getOutputStream();
   }
}

Wireshark enthüllte, dass während des TSL/SSL Hello die Warnung Warnung (Level: Warnung, Beschreibung: Unbekannter Name), Server Hello Vom Server an den Client gesendet wurde . Es war nur eine Warnung. Java 7.1 antwortete daraufhin sofort mit einer "Fatal, Description: Unexpected Message". Dies bedeutet, dass die Java-SSL-Bibliotheken die Warnung vor nicht erkanntem Namen nicht gerne sehen.

Aus dem Wiki zu Transport Layer Security (TLS):

112 Unbekannte Namenswarnung nur für TLS; Der Servernamenindikator des Clients hat einen Hostnamen angegeben, der vom Server nicht unterstützt wird

Dies veranlasste mich dazu, meine Apache-Konfigurationsdateien anzusehen und ich fand heraus, dass ein ServerName oder ServerAlias ​​für den von der Client-/Java-Seite gesendeten Namen korrekt und fehlerfrei funktionierte.

<VirtualHost mydomain.com:443>
  ServerName mydomain.com
  ServerAlias www.mydomain.com
85

Sie können das Senden von SNI-Datensätzen mit der Systemeigenschaft jsse.enableSNIExtension = false deaktivieren. 

Wenn Sie den Code ändern können, ist es hilfreich, SSLCocketFactory#createSocket() zu verwenden (ohne Host-Parameter oder mit einer verbundenen Buchse). In diesem Fall wird keine Angabe zum Servernamen gesendet.

35
eckes

Dieser Fehler ist auch bei einem neuen Apache-Server-Build aufgetreten.

In unserem Fall bestand die Lösung darin, eine ServerAlias im httpd.conf zu definieren, die dem Hostnamen entsprach, zu dem Java eine Verbindung herstellen wollte. Unsere ServerName wurde auf den internen Hostnamen gesetzt. Unser SSL-Zertifikat verwendete den externen Hostnamen. Dies war jedoch nicht ausreichend, um die Warnung zu vermeiden.

Um das Debuggen zu erleichtern, können Sie den folgenden Befehl verwenden:

openssl s_client -servername <hostname> -connect <hostname>:443 -state

Wenn ein Problem mit diesem Hostnamen vorliegt, wird diese Meldung oben in der Ausgabe ausgegeben:

SSL3 alert read: warning:unrecognized name

Ich sollte auch beachten, dass wir diesen Fehler nicht erhalten haben, als dieser Befehl zum Herstellen einer Verbindung zum internen Hostnamen verwendet wurde, obwohl er nicht mit dem SSL-Zertifikat übereinstimmt. 

16
Scott McIntyre

Anstatt sich auf den standardmäßigen virtuellen Hostmechanismus in Apache zu verlassen, können Sie einen letzten catchall virtualhost definieren, der einen beliebigen ServerName und einen Platzhalter-ServerAlias ​​verwendet, z.

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

Auf diese Weise können Sie SNI verwenden, und Apache sendet die SSL-Warnung nicht zurück. 

Dies funktioniert natürlich nur, wenn Sie alle Domains einfach mit einer Platzhaltersyntax beschreiben können.

15
Erik

Es sollte nützlich sein. So wiederholen Sie einen SNI-Fehler in Apache HttpClient 4.4 - der einfachste Weg, den wir gefunden haben (siehe HTTPCLIENT-1522 ):

public class SniHttpClientConnectionOperator extends DefaultHttpClientConnectionOperator {

    public SniHttpClientConnectionOperator(Lookup<ConnectionSocketFactory> socketFactoryRegistry) {
        super(socketFactoryRegistry, null, null);
    }

    @Override
    public void connect(
            final ManagedHttpClientConnection conn,
            final HttpHost Host,
            final InetSocketAddress localAddress,
            final int connectTimeout,
            final SocketConfig socketConfig,
            final HttpContext context) throws IOException {
        try {
            super.connect(conn, Host, localAddress, connectTimeout, socketConfig, context);
        } catch (SSLProtocolException e) {
            Boolean enableSniValue = (Boolean) context.getAttribute(SniSSLSocketFactory.ENABLE_SNI);
            boolean enableSni = enableSniValue == null || enableSniValue;
            if (enableSni && e.getMessage() != null && e.getMessage().equals("handshake alert:  unrecognized_name")) {
                TimesLoggers.httpworker.warn("Server received saw wrong SNI Host, retrying without SNI");
                context.setAttribute(SniSSLSocketFactory.ENABLE_SNI, false);
                super.connect(conn, Host, localAddress, connectTimeout, socketConfig, context);
            } else {
                throw e;
            }
        }
    }
}

und

public class SniSSLSocketFactory extends SSLConnectionSocketFactory {

    public static final String ENABLE_SNI = "__enable_sni__";

    /*
     * Implement any constructor you need for your particular application -
     * SSLConnectionSocketFactory has many variants
     */
    public SniSSLSocketFactory(final SSLContext sslContext, final HostnameVerifier verifier) {
        super(sslContext, verifier);
    }

    @Override
    public Socket createLayeredSocket(
            final Socket socket,
            final String target,
            final int port,
            final HttpContext context) throws IOException {
        Boolean enableSniValue = (Boolean) context.getAttribute(ENABLE_SNI);
        boolean enableSni = enableSniValue == null || enableSniValue;
        return super.createLayeredSocket(socket, enableSni ? target : "", port, context);
    }
}

und

cm = new PoolingHttpClientConnectionManager(new SniHttpClientConnectionOperator(socketFactoryRegistry), null, -1, TimeUnit.MILLISECONDS);
12
Shcheklein

Benutzen:

  • System.setProperty ("jsse.enableSNIExtension", "false");
  • Starten Sie Ihren Tomcat neu (wichtig)
10

Leider können Sie dem jarsigner.exe-Tool keine Systemeigenschaften zur Verfügung stellen.

Ich habe den Fehler 7177232 eingereicht, den @eckes-Fehler 7127374 referenziert und erklärt, warum er fehlerhaft geschlossen wurde.

Mein Fehler betrifft insbesondere die Auswirkungen auf das Jarsigner-Tool, aber möglicherweise führt dies dazu, dass der andere Fehler wieder geöffnet wird und das Problem ordnungsgemäß gelöst wird.

UPDATE: Eigentlich stellt sich heraus, dass Sie das Jarsigner-Tool mit System-Eigenschaften versehen können. Es steht einfach nicht in der Hilfemeldung. Verwenden Sie jarsigner -J-Djsse.enableSNIExtension=false

5
Bob Kerns

Ich habe dieses Problem mit spring boot und jvm 1.7 und 1.8 besprochen. In AWS hatten wir nicht die Möglichkeit, ServerName und ServerAlias ​​entsprechend zu ändern (sie unterscheiden sich). Daher haben wir Folgendes getan:

In build.gradle haben wir folgendes hinzugefügt:

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

Dadurch konnten wir das Problem mit dem "Unbekannten Namen" umgehen.

5
Ray Hunter

Ich traf das gleiche Problem und es stellte sich heraus, dass Reverse DNS nicht korrekt eingerichtet war. Es zeigte auf einen falschen Hostnamen für die IP. Nachdem ich Reverse-DNS korrigiert und httpd neu gestartet habe, ist die Warnung nicht mehr verfügbar.

3
user2888387

Die Variable VirtualHost meines ServerName wurde standardmäßig auskommentiert. Es hat funktioniert, nachdem es unkommentiert war.

2
Aram Paronikyan

Wenn Sie einen Client mit Resttemplate erstellen, können Sie den Endpunkt nur wie folgt festlegen: https: // IP/path_to_service und requestFactory festlegen.
Mit dieser Lösung müssen Sie Ihren Tomcat oder Apache nicht neu starten: 

public static HttpComponentsClientHttpRequestFactory requestFactory(CloseableHttpClient httpClient) {
    TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            return true;
        }
    };

    SSLContext sslContext = null;
    try {
        sslContext = org.Apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }   

    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    final SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext,hostnameVerifier);

    final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", new PlainConnectionSocketFactory())
            .register("https", csf)
            .build();

    final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
    cm.setMaxTotal(100);
    httpClient = HttpClients.custom()
            .setSSLSocketFactory(csf)
            .setConnectionManager(cm)
            .build();

    HttpComponentsClientHttpRequestFactory requestFactory =
            new HttpComponentsClientHttpRequestFactory();

    requestFactory.setHttpClient(httpClient);

    return requestFactory;
}
2
Alfredo

Ich bin auch auf dieses Problem gestoßen, als ich ein Upgrade von Java 1.6_29 auf 1.7 vorgenommen habe.

Alarmierend hat mein Kunde im Java Control Panel eine Einstellung gefunden, die diese auflöst.

Auf der Registerkarte "Erweitert" können Sie "SSL 2.0-kompatibles ClientHello-Format verwenden" aktivieren.

Dies scheint das Problem zu lösen.

Wir verwenden Java-Applets in einem Internet Explorer-Browser.

Hoffe das hilft.

1
Allan D

Einfach hier eine Lösung hinzufügen. Dies kann für LAMP-Benutzer hilfreich sein

Options +FollowSymLinks -SymLinksIfOwnerMatch

Die oben erwähnte Zeile in der Konfiguration des virtuellen Hosts war der Schuldige.

Virtuelle Hostkonfiguration bei Fehler

<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>

Arbeitskonfiguration

<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>
0
Griffin

Ich hatte das gleiche Problem mit einem Ubuntu Linux-Server, auf dem Subversion ausgeführt wurde, wenn über Eclipse darauf zugegriffen wurde.

Es hat sich gezeigt, dass das Problem mit einer Warnung beim Start von Apache zu tun hatte:

[Mon Jun 30 22:27:10 2014] [warn] NameVirtualHost *:80 has no VirtualHosts

... waiting [Mon Jun 30 22:27:11 2014] [warn] NameVirtualHost *:80 has no VirtualHosts

Dies ist auf einen neuen Eintrag in ports.conf zurückzuführen, bei dem neben sites-enabled/000-default eine weitere NameVirtualHost-Direktive eingegeben wurde.

Nach dem Entfernen der Direktive in ports.conf war das Problem verschwunden (nach einem Neustart von Apache natürlich)

0
Gerhard