Ativei o log SSL na JVM Java 8 em uma instância do Linux que reproduz o problema. O registro SSL é ativado usando
-Djavax.net.debug=ssl:handshake:verbose
. Isso revelou algumas informações úteis. A solução alternativa que estamos usando em produção e provou funcionar para nós é definir este parâmetro na JVM:
-Djdk.tls.client.protocols=TLSv1
Se você quiser mais detalhes, por favor leia.
Em um servidor onde o problema pode ser reproduzido (novamente, apenas 5-10% das vezes), observei o seguinte:
*** ClientHello, TLSv1.2
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Handshake, length = 195
main, READ: TLSv1.2 Handshake, length = 1130
*** ServerHello, TLSv1.2
--- 8<-- SNIP -----
%% Initialized: [Session-79, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256]
** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
--- 8<-- SNIP -----
Algorithm: [SHA1withRSA]
--- 8<-- SNIP -----
*** Diffie-Hellman ServerKeyExchange
--- 8<-- SNIP -----
*** ServerHelloDone
*** ClientKeyExchange, DH
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Handshake, length = 133
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Change Cipher Spec, length = 1
*** Finished
verify_data: { 108, 116, 29, 115, 13, 26, 154, 198, 17, 125, 114, 166 }
***
main, WRITE: TLSv1.2 Handshake, length = 40
main, called close()
main, called closeInternal(true)
main, SEND TLSv1.2 ALERT: warning, description = close_notify
main, WRITE: TLSv1.2 Alert, length = 26
main, called closeSocket(true)
main, waiting for close_notify or alert: state 5
main, received EOFException: ignored
main, called closeInternal(false)
main, close invoked again; state = 5
main, handling exception: java.io.IOException: SQL Server returned an incomplete response. The connection has been closed. ClientConnectionId:12a722b3-d61d-4ce4-8319-af049a0a4415
Observe que TLSv1.2 é selecionado pelo servidor de banco de dados e usado nesta troca. Observei que, quando as conexões falham no serviço linux problemático, o TLSv1.2 é SEMPRE o nível selecionado. No entanto, as conexões SEMPRE falham quando o TLSv1.2 é usado. Eles só falham 5-10% do tempo.
Agora aqui está uma troca de um servidor que NÃO tem o problema. Todo o resto é igual. Ou seja, conectando-se ao mesmo banco de dados, mesma versão da JVM (Java 1.8.0_60), mesmo driver JDBC, etc. Observe que, aqui, TLSv1 é selecionado pelo servidor de banco de dados em vez de TLSv1.2 como no caso do servidor defeituoso.
*** ClientHello, TLSv1.2
--- 8<-- SNIP -----
main, WRITE: TLSv1.2 Handshake, length = 207
main, READ: TLSv1 Handshake, length = 604
*** ServerHello, TLSv1
--- 8<-- SNIP -----
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA
--- 8<-- SNIP -----
%% Initialized: [Session-79, TLS_RSA_WITH_AES_128_CBC_SHA]
** TLS_RSA_WITH_AES_128_CBC_SHA
--- 8<-- SNIP -----
Algorithm: [SHA1withRSA]
--- 8<-- SNIP -----
***
*** ServerHelloDone
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1
--- 8<-- SNIP -----
main, WRITE: TLSv1 Handshake, length = 134
main, WRITE: TLSv1 Change Cipher Spec, length = 1
*** Finished
verify_data: { 26, 155, 166, 89, 229, 193, 126, 39, 103, 206, 126, 21 }
***
main, WRITE: TLSv1 Handshake, length = 48
main, READ: TLSv1 Change Cipher Spec, length = 1
main, READ: TLSv1 Handshake, length = 48
*** Finished
Portanto, quando o TLSv1 é negociado entre a JVM do Linux e o SQL Server, as conexões SEMPRE são bem-sucedidas. Quando o TLSv1.2 é negociado, obtemos falhas de conexão esporádicas.
(Observação:Java 7 (1.7.0_51) sempre negocia TLSv1, razão pela qual o problema nunca ocorreu para nós com uma JVM Java 7.)
As questões em aberto que ainda temos são:
- POR QUE é que a mesma JVM Java 8 executada em 2 servidores Linux diferentes sempre negociará TLSv1, mas ao se conectar de outro servidor Linux sempre negociará TLSv1.2.
- E também por que as conexões negociadas TLSv1.2 são bem-sucedidas na maioria das vezes, mas não todas, nesse servidor?
Atualização em 10/06/2017: Esta postagem da Microsoft descreve o problema e sua solução proposta.
Recursos:
http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-with-the-ms14-066-kb-2992611-winshock-mess.html
http://www.infoworld.com/article/2849292/operating-systems/more-patch-problems-reported-with-the-ms14-066-kb-2992611-winshock-mess.html
http://blogs.msdn.com/b/jdbcteam/archive/2008/09/09/the-driver-could-not-establish-a-secure-connection-to-sql-server-by-using-secure- sockets-layer-ssl-encryption.aspx
Java 8, política de força ilimitada JCE e handshake SSL sobre TLS
http://blogs.msdn.com/b/saponsqlserver/archive/2013/05/10/analyzing-jdbc-connection-issues.aspx
https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#descPhase2
https://blogs.oracle.com/java-platform-group/entry/java_8_will_use_tls