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
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.
Le code suivant a fonctionné pour nous dans un environnement d'entreprise dans les conditions suivantes:
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.
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.
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.
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.