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

Случайные исключения "без аутентификации" с использованием Java SSLContextImpl $TLS10Context

Я получаю сбои соединения, которые появляются случайным образом при подключении к HAProxy-серверу с использованием SSL. Я подтвердил, что эти сбои происходят в версиях JDK 1.7.0_21 и 1.7.0_25, но не с 1.7.0_04 или с 1.6.0_38.

Исключение составляет

 Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)
    at SSLTest2.main(SSLTest2.java:52)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Эти сбои возникают только при использовании контекста SSL TLS, а не в контексте по умолчанию. Следующий код запускается в цикле тысячу раз, и неудачи происходят до того, как цикл завершится (около 2% соединений не работают):

SSLContext sslcontext = SSLContext.getInstance("TLS");   
sslcontext.init(null, null, null);
SSLSocketFactory factory = sslcontext.getSocketFactory(); 
SSLSocket socket = (SSLSocket)factory.createSocket("myserver", 443);

//socket.startHandshake();
SSLSession session = socket.getSession();
session.getPeerCertificates();
socket.close();

Если, однако, я создаю контекст SSL таким образом, у меня нет сбоев соединений в любой из версий Java, о которых я упоминал:

SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();

Первый способ использует SSLContextImpl$TLS10Context, а позже использует SSLContextImpl$DefaultSSLContext. Если посмотреть на код, я не вижу различий, которые могли бы вызвать исключение.

Почему я должен получать сбои и какие преимущества/недостатки использования вызова getDefault()?

Примечание. Исключения были впервые обнаружены с использованием Apache HttpClient (версия 4). Этот код является наименьшим подмножеством, которое воспроизводит проблему, наблюдаемую с помощью HttpClient.

Здесь ошибка, которую я вижу при добавлении -Djavax.net.debug=ssl:

main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, bad_record_mac
%% Invalidated:  [Session-101, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA]
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLException: Received fatal alert:   bad_record_mac
main, IOException in getSession():  javax.net.ssl.SSLException: Received fatal alert: bad_record_mac

Другая информация состоит в том, что ошибки не возникают, если я отключу Diffie-Hellman на прокси-сервере.

4b9b3361

Ответ 1

Судя по симптомам, я предполагаю, что это связано с браузерами, использующими TLS false start, что является клиентский трюк Google представил уменьшить количество обратных и последующих в TLS:

False Start во многом контролируется браузером и работает, уменьшая два прохода в оба конца данных, описанных в официальных спецификациях SSL, до одного прохода в оба конца. Он сделал это, поручив клиенту отправлять готовые и первые сообщения ApplicationData в одной диспетчеризации, а не помещать их в два разных пакета и отправлять второй только после получения подтверждения от сервера.

Google предложил False Start в качестве официального стандарта, чтобы сделать SSL более привлекательным для веб-сайтов, которые в настоящее время считают его слишком дорогостоящим. Сокращая рукопожатие, которое согласовывает ключ шифрования и другие переменные, необходимые для защиты данных, проходящих между конечным пользователем и веб-сайтом, False Start предназначался для снижения штрафа за производительность, который, как говорят многие, исходит от использования протокола.

Из релевантная проблема, поднятая в Mozilla Firefox: (внимание мое)

До сих пор в неполном списке продуктов, которые, как известно, имеют текущие или предыдущие проблемы совместимости с False Start, входят (AFAICT): F5, A10, Microsoft TMG, Cisco ASA, ServerIron ADX, ESET, NetNanny, некоторые конфигурации реализации Java SSL-сервера.

Ответ 2

javax.net.ssl.SSLPeerUnverifiedException возникает только из-за защиты http, вы должны настроить свое соединение как https, следуйте этому коду.

            SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(null, new TrustManager[]{tm}, null);
    SSLSocketFactory ssf = new SSLSocketFactory(ctx);
    ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    ClientConnectionManager ccm = client.getConnectionManager();
    SchemeRegistry sr = ccm.getSchemeRegistry();
    sr.register(new Scheme("https", ssf, 443));
    return new DefaultHttpClient(ccm, client.getParams());

используйте это. я надеюсь, что это поможет вам