Как сделать так, чтобы Java 6, которая не поддерживает SSL-соединение с SSL-одноранговым узлом, отключилась неправильно, как Java 7?

Я вижу, что SSL-соединение от клиента, работающего под управлением Java 6, не работает с исключением, например:

Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:882)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1215)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
    ... 35 more
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:462)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863)
    ... 41 more

Сервер представляет собой приложение на основе Tomcat 7, работающее на Java 7, Linux и Amazon EC2, чего это стоит.

Я нашел много предложений по возможным причинам, включая случайное подключение к порту, отличному от SSL, и т. Д. Я считаю, что исключил все это, в основном потому, что тот же самый клиент работает при запуске Java 7 без изменить. (OS X в обоих случаях.)

Ниже я привожу отладочные данные процедуры SSL-соединения Java 6 и Java 7. Мой вопрос к экспертам: предполагает ли это, что некоторые возможные настройки шифра или протокола, возможно, по умолчанию в Java 7, могут быть включены в Java 6, чтобы заставить его работать?

Java 6:

Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1363993281 bytes = { 77, 153, 100, 72, 45, 178, 253, 243, 195, 167, 17, 151, 39, 247, 148, 102, 213, 129, 39, 17, 26, 139, 157, 154, 63, 88, 41, 160 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
***
main, WRITE: TLSv1 Handshake, length = 81
main, WRITE: SSLv2 client hello message, length = 110
main, received EOFException: error
main, handling exception: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
main, SEND TLSv1 ALERT:  fatal, description = handshake_failure
main, WRITE: TLSv1 Alert, length = 2
main, called closeSocket()

Java 7:

Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
main, setSoTimeout(0) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1363993435 bytes = { 131, 83, 80, 186, 215, 90, 171, 131, 231, 18, 184, 183, 249, 155, 197, 204, 73, 1, 74, 79, 32, 142, 236, 28, 111, 37, 58, 255 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: ec2-xx-xx-xx-xx.compute-1.amazonaws.com]

person Sean Owen    schedule 23.03.2013    source источник
comment
Виден ли сбой со стороны клиента? Я видел ошибки такого типа раньше как часть обычного согласования SSL, то есть это работало с точки зрения пользователя.   -  person Taylor    schedule 23.03.2013
comment
В Java 6 клиентское приветствие возвращается к SSLv2, тогда как с Java 7, похоже, выполняется с TLSv1. Я считаю, что JSSE под Java 6 официально не поддерживает SSL V2, но мне нужно исследовать это   -  person Bruno Grieder    schedule 23.03.2013
comment
Используя `openssl s_client -connect servername: 443`, вы можете отладить, какой протокол поддерживает сервер, и выполнить тесты, установив такие флаги, как ssl2, ssl2, отметьте это   -  person Bruno Grieder    schedule 23.03.2013
comment
@Taylor да, запрос каждый раз терпит неудачу в Java 6, и соединение не устанавливается.   -  person Sean Owen    schedule 23.03.2013
comment
@BGR да, я подтвердил, что он поддерживает только tls1 и ssl3, как я и ожидал. Теперь я смотрю, как заставить Java 6 не использовать SSLv2.   -  person Sean Owen    schedule 23.03.2013
comment
@SeanOwen - как отладить эту проблему и выяснить причину? т.е. придете к тому же решению, что и вы?   -  person MasterJoe    schedule 21.07.2017


Ответы (5)


Бруно в конце концов дал правильный ответ. Это проще всего контролировать с помощью системного свойства https.protocols. Таким образом вы можете контролировать, что возвращает фабричный метод. Например, установите "TLSv1".

person Community    schedule 31.03.2013
comment
Это приводит к проблемам, когда вы хотите использовать два протокола вместо одного. Например, SSLv3 и TLSv1. Это -Dhttps.protocols=TLSv1,SSLv3 приведет к исключениям, если вы попытаетесь подключить SSLv3 или TLSv1. - person Dragon; 04.12.2013
comment
@Dragon Правда? Какие исключения? Почему? - person user207421; 13.05.2015

Похоже, что в журнале отладки для Java 6 запрос отправляется в формате SSLv2.

main, WRITE: приветственное сообщение клиента SSLv2, длина = 110

Это не упоминается как включенное по умолчанию в Java 7.
Измените клиент, чтобы использовать SSLv3 и выше, чтобы избежать таких проблем с совместимостью.

Ищите различия в JSSE провайдерах в Java 7 и Java 6

person Cratylus    schedule 23.03.2013
comment
Да, это хорошее доказательство, и действительно проблема с SSLv2. Это приводит к моему ответу здесь, хотя @EJP прав в том, что было бы лучше найти способ явно отключить SSLv2. - person Sean Owen; 24.03.2013

Удалите «SSLv2ClientHello» из включенных протоколов на клиентском SSLSocket или HttpsURLConnection.

person user207421    schedule 23.03.2013
comment
Я думаю, что это совершенно правильно, хотя и не знаю, как это сделать. Я строю SSLSocketFactory для платформы. SSLContext.createSSLEngine() создает SSLEngine, у которого есть методы для установки (а не удаления, кажется,) протоколов. Но я не думаю, что это помогает SSLSocketFactory. SSLContext также позволяет вам запрашивать протокол и не отключать все остальные, которые влекут за собой (?). Если вы знаете, как это происходит, дайте мне знать. - person Sean Owen; 24.03.2013
comment
Получите включенные протоколы, удалите SSLv2ClientHello и установите для них то, что осталось. - person user207421; 24.03.2013
comment
Хотя я не верю, что есть такой метод. По крайней мере, я не вижу этого на SSLContext или SSLSocketFactory. SSLEngine, я считаю, бесполезен, поскольку фреймворк будет создан позже. Будем искать. - person Sean Owen; 24.03.2013
comment
Любой такой метод, как что? О чем ты говоришь? getEnabledCipherSuites () и setEnabledCipherSuites () существуют. Вы также можете установить системное свойство, чтобы управлять этим для SSLContext по умолчанию. - person user207421; 24.03.2013
comment
Да, @EJP, но это на SSLSocket, и я делаю фабрику ... что, вероятно, означает обертывание пользовательским SSLSocketFactory. Похоже, должно быть что-то более чистое. Я поищу это системное свойство. - person Sean Owen; 24.03.2013
comment
@SeanOwen, если вы используете HttpsURLConnection, _ 2_ системное свойство должно помочь вам установить включенные наборы шифров. - person Bruno; 25.03.2013
comment
Подтверждено, что -Dhttps.protocols=TLSv1 выполняет эту работу в Java 6. - person Sean Owen; 26.03.2013
comment
@SeanOwen Если вы создаете фабрику сокетов, вы получаете сокет или создаете его самостоятельно, и вы можете вызывать эти методы, прежде чем вернуть их. - person user207421; 13.05.2015

обновите аргументы сервера с -Dhttps.protocols = SSLv3 до -Dhttps.protocols = TLSv1, SSLv3

person Alekya    schedule 05.01.2015

Делай это так:

SSLSocket socket = (SSLSocket) sslFactory.createSocket(host, port);
socket.setEnabledProtocols(new String[]{"SSLv3", "TLSv1"});
person Martin Wickman    schedule 27.12.2013