configurar - tomcat 8 https
¿Qué significa "javax.net.ssl.SSLHandshakeException: el cambio del certificado del servidor está restringido durante la renegociación" y cómo prevenirlo? (4)
Este mensaje de error en el código de la capa del cliente es una consecuencia de la consolidación del código después de la vulnerabilidad de Poodle de SSL V3.0 (CVE-2014-3566) en las últimas actualizaciones de Java. Y es un error: aquí están las soluciones en caso de que no pueda actualizar su JRE inmediatamente:
Una primera opción es forzar el protocolo TLS al establecer una conexión HTTPS:
Si puede actualizar HttpClient a una versión más reciente que la 4.3.6, entonces SSLv3 se desactivará de manera predeterminada y su código ya no deberá informar dicha excepción.
Si no puede actualizar su versión de HttpClient, tendrá que usar el código de esta respuesta para restringir los protocolos a TLS: https://stackoverflow.com/a/26439487/737790
Para otros accesos HTTP desde el tiempo de ejecución de Java 7, se debe establecer la siguiente propiedad del sistema
-Dhttps.protocols="TLSv1"
Los detalles completos se pueden encontrar aquí: clientes http de Java y POODLE
Una segunda opción es relajar el control del cliente para permitir aún la renegociación con las siguientes propiedades:
-Djdk.tls.allowUnsafeServerCertChange=true
-Dsun.security.ssl.allowUnsafeRenegotiation=true
Una tercera opción es "mejorar" sus certificados de servidor para incluir todas las direcciones IP de los miembros de su clúster como Nombres alternativos de sujeto de acuerdo con esta publicación en el foro de Burp.
Una cuarta opción es degradar su versión de Java antes de que se hayan agregado las verificaciones de certificado / renegociación, por lo tanto, antes de 7u41 (por confirmar)
Actualizaciones Este comportamiento de error ahora está arreglado en las actualizaciones JDK 7u85 y 8u60. Créditos a Pada por haber encontrado la referencia JDK-8072385 .
Usamos Oracle jdk 1.7.0_71 y Tomcat 7.0.55. Lamentablemente, comenzamos a obtener la siguiente excepción durante la conexión SSL entre servidores:
javax.net.ssl.SSLHandshakeException: server certificate change is restrictedduring renegotiation
¿Qué significa? ¿Cómo prevenirlo?
La excepción desaparece después del reinicio de Tomcat.
La pila completa:
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
Esto también puede deberse a una conectividad mal configurada, como un haproxy con uno o más objetivos de equilibrio de carga que apuntan a una dirección IP incorrecta, de modo que X por ciento de las solicitudes obtienen un certificado diferente.
La siguiente pieza de código funcionó para nosotros en un entorno empresarial en las siguientes condiciones;
- la actualización del certificado sin interrupciones (tiempo de ejecución) es un requisito crítico
- es demasiado costoso actualizar el HTTPClient utilizado en la aplicación
- restringir el protocolo https a "TLSv1" no tiene efecto
- la aplicación es un cliente Java servido por JNLP y ni el "allowUnsafeServerCertChange" ni el "allowUnsafeRenegotiation" no pueden pasar a la aplicación cliente mediante argumentos JNLP (supongo que JWS los está bloqueando por razones de seguridad)
la configuración de "allowUnsafeServerCertChange" y "allowUnsafeRenegotiation" mediante las llamadas a System.setProperty () durante el arranque de la aplicación no tiene ningún efecto.
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); } }
Tenga en cuenta que esto debe considerarse como un hack (que introduce una vulnerabilidad) y debe usarse en un entorno confiable. Uno debe probar todas las opciones en la respuesta de Yves antes de seguir por este camino.
Obtuve este problema porque el lado del servidor actualizó sus certificados. Antes de esto, nuestro cliente estaba trabajando bien. Simplemente reiniciamos nuestro programa y volvió a la normalidad nuevamente.