Подтвердить что ты не робот

Что означает "javax.net.ssl.SSLHandshakeException: изменение сертификата сервера ограничено во время пересмотра" и как его предотвратить?

Мы используем Oracle jdk 1.7.0_71 и Tomcat 7.0.55. К сожалению, при соединении SSL между серверами мы стали получать следующее исключение:

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

Что это значит? Как предотвратить это?

Исключение исчезает после перезапуска Tomcat.

Полный стек:

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

Ответ 1

Это сообщение об ошибке в коде клиентского уровня является следствием ужесточения кода после "Уязвимости пуделя SSL V3.0 - CVE-2014-3566" в последних обновлениях Java. И это ошибка - вот обходные ситуации, если вы не можете сразу обновить JRE:

Первым вариантом является принудительный протокол TLS при установлении соединения HTTPS:

Если вы можете обновить HttpClient до более поздней версии, чем 4.3.6, тогда SSLv3 будет отключен по умолчанию, и ваш код больше не будет сообщать об этом исключении.

Если вы не можете обновить версию HttpClient, вам придется использовать этот код ответа, чтобы ограничить протоколы TLS: fooobar.com/questions/156649/...

Для другого HTTP-доступа из среды выполнения Java 7 необходимо установить следующее системное свойство

-Dhttps.protocols="TLSv1"

Подробную информацию можно найти здесь: HTTP-клиенты Java и POODLE


Второй вариант - это отменить проверку клиента, чтобы все еще разрешить пересмотр со следующими свойствами:

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


Третий вариант заключается в том, чтобы "улучшить" ваши сертификаты сервера, чтобы включить все IP-адреса ваших членов кластера в качестве альтернативных имен объектов в соответствии с this сообщение в форуме Burp


Четвертый вариант заключается в том, чтобы понизить версию Java до того, как эти проверки сертификата/пересмотра были добавлены, поэтому до 7u41 (для подтверждения)

Обновления. Это поведение багги теперь исправлено в обновлениях JuK 7u85 и 8u60. Кредиты для Pada за обнаружение JDK-8072385.

Ответ 2

Следующая часть кода работала для нас в корпоративной среде при следующих условиях:

  • Обновление
  • бесшовного (run-time) сертификата является критическим требованием
  • Это слишком дорого для обновления HTTPClient, используемого в приложении
  • ограничение https-протокола на "TLSv1" не влияет
  • приложение является JNLP обслуживаемым java-клиентом, и никакие "allowUnsafeServerCertChange" и "allowUnsafeRenegotiation" не могут быть переданы в клиентское приложение через аргументы JNLP (я предполагаю, что JWS блокирует их из-за соображений безопасности)
  • установка "allowUnsafeServerCertChange" и "allowUnsafeRenegotiation" через вызовы System.setProperty() во время загрузки приложения не имеет эффекта.

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

Обратите внимание, что это следует рассматривать как взлом (введение уязвимости) и должно использоваться в надежной среде. Прежде чем идти по этому пути, нужно попробовать все варианты ответа Ив.

Ответ 3

Это также может быть связано с неверно настроенной связностью, такой как haproxy с одной или несколькими целями баланса нагрузки, указывающими на неправильный IP-адрес, так что X процентов запросов получают другой сертификат.

Ответ 4

У меня возникла эта проблема, потому что серверная часть обновила свои сертификаты. До этого наш клиент работал нормально. Мы просто перезапустили нашу программу, и она снова вернулась к нормальной работе.