web-dev-qa-db-fra.com

Que signifie "javax.net.ssl.SSLHandshakeException: la modification du certificat de serveur limite la renégociation" et comment l’empêcher?

Nous utilisons Oracle jdk 1.7.0_71 et Tomcat 7.0.55 . Malheureusement, nous avons commencé à obtenir l'exception suivante lors de la connexion SSL entre serveurs:

javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation

Qu'est-ce que cela signifie? Comment l'éviter?

L'exception a disparu après le redémarrage de Tomcat.

La pile complète:

Caused by: javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation
        at Sun.security.ssl.Alerts.getSSLException(Alerts.Java:192) ~[?:1.7.0_71]
        at Sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.Java:1884) ~[?:1.7.0_71]
        at Sun.security.ssl.Handshaker.fatalSE(Handshaker.Java:276) ~[?:1.7.0_71]
        at Sun.security.ssl.Handshaker.fatalSE(Handshaker.Java:266) ~[?:1.7.0_71]
        at Sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.Java:1402) ~[?:1.7.0_71]
        at Sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.Java:209) ~[?:1.7.0_71]
        at Sun.security.ssl.Handshaker.processLoop(Handshaker.Java:878) ~[?:1.7.0_71]
        at Sun.security.ssl.Handshaker.process_record(Handshaker.Java:814) ~[?:1.7.0_71]
        at Sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.Java:1016) ~[?:1.7.0_71]
        at Sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.Java:1312) ~[?:1.7.0_71]
        at Sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.Java:702) ~[?:1.7.0_71]
        at Sun.security.ssl.AppOutputStream.write(AppOutputStream.Java:122) ~[?:1.7.0_71]
        at Java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.Java:82) ~[?:1.7.0_71]
        at Java.io.BufferedOutputStream.flush(BufferedOutputStream.Java:140) ~[?:1.7.0_71]
        at org.Apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.Java:506) ~[commons-httpclient-3.1.jar:?]
        at org.Apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.Java:2114) ~[commons-httpclient-3.1.jar:?]
        at org.Apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.Java:1096) ~[commons-httpclient-3.1.jar:?]
        at org.Apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.Java:398) ~[commons-httpclient-3.1.jar:?]
        at org.Apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.Java:171) ~[commons-httpclient-3.1.jar:?]
        at org.Apache.commons.httpclient.HttpClient.executeMethod(HttpClient.Java:397) ~[commons-httpclient-3.1.jar:?]
        at org.Apache.commons.httpclient.HttpClient.executeMethod(HttpClient.Java:323) ~[commons-httpclient-3.1.jar:?]
        at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.executePostMethod(CommonsHttpInvokerRequestExecutor.Java:205) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor.doExecuteRequest(CommonsHttpInvokerRequestExecutor.Java:140) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor.executeRequest(AbstractHttpInvokerRequestExecutor.Java:136) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.Java:192) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.executeRequest(HttpInvokerClientInterceptor.Java:174) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.invoke(HttpInvokerClientInterceptor.Java:142) ~[spring-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
        ... 160 more
40
Michael

Ce message d'erreur dans le code de couche client est une conséquence du durcissement du code après la "Vulnérabilité liée au protocole SSL V3.0 - CVE-2014-3566" dans les dernières mises à jour de Java. Et c'est un bogue - voici des solutions de contournement au cas où vous ne pourriez pas mettre à jour votre JRE immédiatement:

Une première option consiste à forcer le protocole TLS lors de l'établissement d'une connexion HTTPS:

Si vous pouvez mettre à jour HttpClient vers une version plus récente que la version 4.3.6, SSLv3 sera désactivé par défaut et votre code ne devrait plus signaler une telle exception.

Si vous ne pouvez pas mettre à niveau votre version de HttpClient, vous devrez utiliser le code de cette réponse pour restreindre les protocoles à TLS: https://stackoverflow.com/a/26439487/737790

Pour les autres accès HTTP à partir de Java 7, la propriété système suivante doit être définie.

-Dhttps.protocols="TLSv1"

Vous trouverez tous les détails ici: Clients Java http et POODLE


Une deuxième option consiste à assouplir la vérification du client pour toujours autoriser la renégociation avec les propriétés suivantes:

-Djdk.tls.allowUnsafeServerCertChange=true 
-Dsun.security.ssl.allowUnsafeRenegotiation=true


Une troisième option consiste à "améliorer" vos certificats de serveur afin d'inclure toutes les adresses IP des membres de votre cluster en tant que sujets. Noms alternatifs selon ce message dans le forum Burp


Une quatrième option consiste à rétrograder votre version de Java avant que ces vérifications de certificat/renégociation ne soient ajoutées, donc avant 7u41 (à confirmer)

Updates Ce problème a maintenant été résolu dans les mises à jour JDK 7u85 et 8u60. Crédits à Pada pour avoir trouvé la JDK-8072385 référence.

46
Yves Martin

Le code suivant a fonctionné pour nous dans un environnement d'entreprise dans les conditions suivantes:

  • la mise à jour transparente du certificat (au moment de l'exécution) est une exigence essentielle
  • il est trop coûteux de mettre à jour le HTTPClient utilisé dans l'application
  • restreindre le protocole https à "TLSv1" n'a pas d'effet
  • l'application est un client Java desservi par JNLP et ni "allowUnsafeServerCertChange" ni "allowUnsafeRenegotiation" ne peuvent pas être transmis à l'application client via des arguments JNLP (je suppose que JWS les bloque pour des raisons de sécurité)
  • la définition des paramètres "allowUnsafeServerCertChange" et "allowUnsafeRenegotiation" via les appels System.setProperty () lors du démarrage de l'application n'a aucun effet.

    if (e.getCause() instanceof SSLHandshakeException) {
        logger.debug("server https certificate has been altered");
        try {
            Class<?> c = Class.forName("Sun.security.ssl.ClientHandshaker");
            Field allowUnsafeServerCertChangeField = c.getDeclaredField("allowUnsafeServerCertChange");
            allowUnsafeServerCertChangeField.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(allowUnsafeServerCertChangeField, allowUnsafeServerCertChangeField.getModifiers() & ~Modifier.FINAL);
            allowUnsafeServerCertChangeField.set(null, true);
            logger.debug("client has been updated in order to support SSL certificate change (re-negotiation) on runtime.");
        }
        catch (Exception ex) {
            logger.debug("client cannot be updated to support SSL certificate change (re-negotiation) on runtime. Please restart the application.", ex);
        }
    }
    

Veuillez noter que ceci doit être considéré comme un hack (introduisant une vulnérabilité) et doit être utilisé dans un environnement sécurisé. Yves devrait essayer toutes les options de la réponse avant de s'engager dans cette voie.

5
Mert Z.

Cela peut également être dû à une connectivité mal configurée, telle qu'un haproxy avec une ou plusieurs cibles d'équilibrage de charge pointant vers la mauvaise adresse IP, de sorte que X% des demandes obtiennent un certificat différent.

2
nbryant

J'ai eu ce problème parce que le côté serveur a mis à jour leurs certificats. Avant cela, notre client fonctionnait bien. Nous avons simplement redémarré notre programme et il est revenu à la normale.

1
Charlie

J'ai eu ce problème et il s'est avéré que le client appelant le service avec un certificat différent derrière un équilibreur de charge. 

0
John