Java Apache HTTP服务器出现间歇性SSL握手错误
我看到Java客户端和浏览器通过Apache HTTP服务器访问站点时出现间歇性SSL握手错误。这种情况很少发生,但每天都会破坏构建并影响用户体验。服务器配置为建立安全连接,但不需要来自客户端的证书 我已经在Java测试客户端和服务器上打开了SSL调试输出(见下文)。我所观察到的是,每当发生握手异常时,服务器似乎已经发送了对客户端证书的请求。我不明白为什么它会这样做,为什么这只是偶尔发生。当它发送证书请求时,错误几乎总是发生,但是我也捕获了成功的请求(可能有1%的时间,99%的时间失败) 客户端使用Java 8(1.8.0_31-b13),Apache HTTP服务器版本为2.2.19 以下是日志中的片段: 1) Apache配置摘录Java Apache HTTP服务器出现间歇性SSL握手错误,java,apache,ssl,handshake,Java,Apache,Ssl,Handshake,我看到Java客户端和浏览器通过Apache HTTP服务器访问站点时出现间歇性SSL握手错误。这种情况很少发生,但每天都会破坏构建并影响用户体验。服务器配置为建立安全连接,但不需要来自客户端的证书 我已经在Java测试客户端和服务器上打开了SSL调试输出(见下文)。我所观察到的是,每当发生握手异常时,服务器似乎已经发送了对客户端证书的请求。我不明白为什么它会这样做,为什么这只是偶尔发生。当它发送证书请求时,错误几乎总是发生,但是我也捕获了成功的请求(可能有1%的时间,99%的时间失败) 客户端
SSLProtocol ALL -SSLv2 -SSLv3
SSLCertificateFile <path-to-pem1>
SSLCertificateChainFile <path-to-pem2>
SSLCACertificateFile <path-to-pem3>
SSLVerifyDepth 10
SSLVerifyClient none
3) 服务器日志(缩写)
在好的情况下,我们始终不会在客户端看到“***CertificateRequest”,也不会在服务器上看到这样的输出
[debug] ssl_engine_kernel.c(1987): [client x.x.x.x] SSL virtual host for servername XXX found
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client hello A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server hello A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write certificate A
[debug] ssl_engine_kernel.c(1274): [client x.x.x.x] handing out temporary 1024 bit DH key
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write key exchange A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 write server done A
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 flush data
[debug] ssl_engine_io.c(1897): OpenSSL: read 5/5 bytes from BIO#82d82d8 [mem: 82c8790] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: 16 03 01 00 86 ..... |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1897): OpenSSL: read 134/134 bytes from BIO#82d82d8 [mem: 82c8795] (BIO dump follows)
[debug] ssl_engine_io.c(1830): +-------------------------------------------------------------------------+
[debug] ssl_engine_io.c(1869): | 0000: XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX ................ |
...
[debug] ssl_engine_io.c(1869): | 0080: XX XX XX XX XX XX ...... |
[debug] ssl_engine_io.c(1875): +-------------------------------------------------------------------------+
[debug] ssl_engine_kernel.c(1874): OpenSSL: Loop: SSLv3 read client key exchange A
Java客户端代码大纲:
URL url = new URL("https://...");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " + DatatypeConverter.printBase64Binary((user + ":" + pass).getBytes(Charset.forName("UTF-8"))));
connection.setReadTimeout(60*1000);
connection.setUseCaches(false);
connection.connect();
跑
java -Djavax.net.ssl.trustStore=... -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=... -Djavax.net.debug=all ...
问题:
SSL\u CTX\u set\u client\u CA\u list
。这是一个著名的名字列表。另请参阅
服务器还需要调用SSL\u CTX\u load\u verify\u locations
来建立CAs中的信任。另见
设置“SSLVerifyClient none”是否不阻止证书请求 可能吧。从中,您需要
SSL\u-VERIFY\u-PEER
,如果没有对等证书,则可能需要SSL\u-VERIFY\u-FAIL\u
对下一步该看什么有什么建议吗
您应该显示相关的Java代码
您应该说明服务器和客户端使用的OpenSSL版本
是什么使服务器发送证书请求,从而导致客户端上的输出“***CertificateRequest”
您可能在.htaccess文件中将SSLVerifyClient
设置为“可选”或更高版本,这就是您在配置文件中找不到它的原因。这将覆盖全局设置的“SSLVerifyClient none”。经过长时间、繁琐的调试和分析,我想报告结果。问题与客户端发送的TLS握手的第一条ClientHello
消息有关
Java7和Java8客户端(可能包括所有现代浏览器)使用“服务器名称指示”(SNI)扩展。此问题仅在使用此扩展时发生。Java6客户机不发送它,而且问题从未在那里发生过。TLSv1和TLSv1.2出现问题-我们从未观察到TLSv1.1请求,因此我无法发表评论
对于Java 7和Java 8客户端,为了防止该问题,我们可以设置-djse.enableSNIExtension=false
,以停止客户端发送SNI扩展
我们将尝试更改httpd.conf
配置(以及包含的文件),看看是否可以让服务器正常工作。如果我们成功,我可能会发布信息,例如,是否有服务器端解决方案。上述Java交换机是一个客户端解决方案,至少对于我们的夜间构建来说足够好。它在CertificateRequest中发送给客户端。没有理由发送它。添加了Java示例代码,OpenSSL没有在那里使用。我无法接触到真正的机器。系统管理员告诉我已安装“OpenSSL 1.0.1h 2014年6月5日,扩展3.0.16.0”。我假设Apache使用共享libs,系统管理员告诉我周围没有.htaccess文件。但是,“SSLVerifyClient none”仅在节中配置。将它升级到httpd.conf(全局)-看起来很有希望,但我明天会知道更多。仍然让我困惑的是,为什么这个问题只会偶尔出现。在某个地方或其他地方,它的配置高于“无”。否则不会发送CertificateRequest。这是毫无疑问的。非常感谢你的帮助!由于我无法控制的情况,进展极其缓慢。我要求配置mod_info,以便在运行时显示配置;可能会显示意外的SSLVerifyClient设置。我通过启动一个新的JVM并反复访问同一个URL来生成零星的证书请求。这些调用中的一小部分显示证书请求并失败。你知道为什么这只会偶尔发生吗?据我所知,证书请求是服务器SSL状态的一部分,为什么它会对同一请求做出不同的反应?配置des没有显示“SSLVerifClient”设置为“none”以外的任何值。我认为我们在mod_ssl或openssl实现中看到了一个问题。我在使用jre 8的tomcat8.5上遇到了这个问题。不幸的是,禁用SNI并不能修复它(至少在我的情况下)。
URL url = new URL("https://...");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " + DatatypeConverter.printBase64Binary((user + ":" + pass).getBytes(Charset.forName("UTF-8"))));
connection.setReadTimeout(60*1000);
connection.setUseCaches(false);
connection.connect();
java -Djavax.net.ssl.trustStore=... -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStorePassword=... -Djavax.net.debug=all ...