237 votes

Alerte de prise de contact SSL: erreur de nom non reconnu depuis la mise à niveau vers Java 1.7.0

Je suis passé de Java 1.6 à Java 1.7 aujourd'hui. Depuis lors une erreur se produit lorsque j'essaie d'établir une connexion à mon serveur web via 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)
 

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

C'est seulement un projet de test c'est pourquoi j'autorise et utilise des certificats non approuvés avec le 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);
    } 
 

J'ai essayé avec succès de me connecter à https://google.com . où est ma faute?

Merci.

314voto

Lekensteyn Points 22873

Java 7 a introduit SNI de soutien qui est activé par défaut. J'ai trouvé que certains serveurs mal configurés envoyer un "non reconnus" Nom d'avertissement dans le handshake SSL qui est ignoré par la plupart des clients... sauf pour Java. Comme @Bob Kerns mentionné, l'Oracle des ingénieurs refuser de "réparer" ce bug/feature.

Comme solution de contournement, ils proposent de définir l' jsse.enableSNIExtension de la propriété. Pour permettre à vos programmes fonctionnent sans re-compiler, exécuter votre application:

java -Djsse.enableSNIExtension=false yourClass

La propriété peut également être définie dans le code Java, mais il doit être défini avant toute SSL actions. Une fois la bibliothèque SSL est chargé, vous pouvez modifier la propriété, mais il n'aura aucun effet sur la SNI état. Pour désactiver la SNI de l'exécution (avec les limites mentionnées), utilisez:

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

L'inconvénient de cette option est que le SNI est désactivé partout dans l'application. Afin de rendre l'utilisation de la SNI et soutiennent encore mal configuré les serveurs:

  1. Créer un SSLSocket le nom d'hôte que vous souhaitez vous connecter. Laissez le nom de cette sslsock.
  2. Essayez d'exécuter sslsock.startHandshake(). Cela va bloquer jusqu'à ce qu'il se fait ou lève une exception en cas d'erreur. Chaque fois qu'une erreur s'est produite en startHandshake(), obtenez le message d'exception. S'il est égal à handshake alert: unrecognized_name, alors vous avez trouvé un problème de configuration du serveur.
  3. Lorsque vous avez reçu l' unrecognized_name d'avertissement (fatal en Java), une nouvelle tentative d'ouverture d'un SSLSocket, mais cette fois sans un nom d'hôte. Cela permet de désactiver le SNI (après tout, la SNI extension est sur l'ajout d'un nom d'hôte pour le message ClientHello).

Pour le Webscarab proxy SSL, ce commit met en œuvre le repli de l'installation.

92voto

David McLaughlin Points 461

J'ai eu ce que je crois le même problème. J'ai trouvé que j'avais besoin d'ajuster la configuration d'Apache pour inclure un nom de serveur ou de la directive ServerAlias pour l'hôte.

Ce code a échoué:

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

Et ce code a fonctionné:

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 révélé qu'au cours de la TSL/SSL Bonjour l'avertissement D'Alerte (Niveau: Avertissement Description: Unrecognized Nom), Serveur Bonjour, A été envoyé à partir du serveur vers le client. Ce n'était qu'un avertissement, cependant, Java 7.1 ensuite répondu immédiatement en arrière avec un "Fatal, Description: Message Inattendu", ce qui je suppose signifie que le Java bibliothèques SSL n'aime pas à voir l'avertissement de non reconnues nom.

À partir du Wiki sur TLS (Transport Layer Security):

112 Méconnue nom d'avertissement TLS uniquement; Serveur du client Nom de l'Indicateur spécifié un nom d'hôte pas pris en charge par le serveur

Cela m'a conduit à regarder mes fichiers de configuration d'Apache et j'ai trouvé que si j'ai ajouté un nom de serveur ou de la directive ServerAlias pour le nom envoyées par le client/java côté, il a fonctionné correctement sans erreur.

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

38voto

eckes Points 1191

Vous pouvez désactiver l'envoi d'enregistrements SNI avec la propriété System jsse.enableSNIExtension = false.

Si vous pouvez changer le code, il est utile d'utiliser SSLCocketFactory#createSocket() (sans paramètre hôte ou avec un socket connecté). Dans ce cas, il n'enverra pas d'indication de nom de serveur.

15voto

Erik Points 51

Au lieu de s'appuyer sur le mécanisme d'hôte virtuel par défaut dans apache, vous pouvez définir un dernier virtualchaost catchall qui utilise un ServerName arbitraire et un ServerAlias ​​générique, par exemple

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

De cette façon, vous pouvez utiliser SNI et Apache ne renverra pas l'avertissement SSL.

Bien sûr, cela ne fonctionne que si vous pouvez décrire facilement tous vos domaines en utilisant une syntaxe générique.

5voto

Bob Kerns Points 497

Vous ne pouvez pas fournir les propriétés du système pour l'jarsigner.exe outil, malheureusement.

J'ai soumis défaut 7177232, référencement @eckes " défaut 7127374 et à expliquer pourquoi il a été fermé par erreur.

Mon défaut est précisément à propos de l'impact sur l'jarsigner outil, mais peut-être qu'il les conduira à la réouverture de l'autre défaut et de traiter le problème correctement.

Mise à JOUR: en Fait, il s'avère que vous POUVEZ fournir les propriétés du système pour la Jarsigner outil, c'est juste pas dans le message d'aide. Utiliser jarsigner -J-Djsse.enableSNIExtension=false

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X