use*_*486 50 java ssl haproxy sslsocketfactory
当使用SSL连接到HAProxy服务器时,我会出现随机出现的连接失败.我已经确认这些故障发生在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)
Run Code Online (Sandbox Code Playgroud)
这些故障仅在使用TLS SSL上下文而非默认上下文时发生.以下代码在循环中运行了一千次,并且在循环完成之前发生了故障(大约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();
Run Code Online (Sandbox Code Playgroud)
但是,如果我以这种方式创建SSL上下文,我在上面提到的任何Java版本上都没有连接失败:
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
Run Code Online (Sandbox Code Playgroud)
第一种方式使用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
Run Code Online (Sandbox Code Playgroud)
另一条信息是,如果我关闭代理服务器上的Diffie-Hellman,则不会发生错误.
小智 1
从症状来看,我猜测这与使用TLS false start 的浏览器有关,这是 Google 引入的客户端技巧,用于减少 TLS 中的来回:
False Start 主要由浏览器控制,其工作原理是将官方 SSL 规范中描述的数据的两次往返传递减少为一次往返传递。它通过指示客户端在一次调度中发送 Finished 和第一个 ApplicationData 消息来实现此目的,而不是将它们放入两个不同的包中并仅在获得服务器确认后才发送第二个包。
Google 提议将 False Start 作为官方标准,以使目前认为提供 SSL 成本太高的网站更容易接受。通过缩短协商加密密钥和保护最终用户和网站之间数据传递所需的其他变量的握手,“虚假启动”旨在降低许多人所说的使用该协议带来的性能损失。
来自Mozilla Firefox 中提出的相关问题:(强调我的)
到目前为止,已知当前或之前存在 False Start 兼容性问题的不完整产品列表包括 (AFAICT):F5、A10、Microsoft TMG、Cisco ASA、ServerIron ADX、ESET、NetNanny、Java SSL 服务器实现的一些配置。