我们必须使用 HTTPS 将我们的应用程序(用 Java 8 编写)连接到一些非常旧的服务器。作为 Java 8,我们的客户端支持 TLSv1.2、TLSv1.1、TLSv1 和 SSLv3。当然,它更喜欢使用 TLSv1.2,因为它是最新的协议。
但是,服务器 (Oracle-HTTP-Server 11.1.1.7) 仅支持 TLSv1 和 SSLx。此外,它支持的密码套件选择非常有限,但仍有一个共同的套件可以与 TLSv1 一起使用:SSL_RSA_WITH_3DES_EDE_CBC_SHA(又名 TLS_RSA_WITH_3DES_EDE_CBC_SHA)。
但是,直接连接会因服务器终止握手而失败。我们得到的调试输出(在客户端)如下所示:
main, WRITE: TLSv1.2 Handshake, length = 265
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1.2 ALERT: fatal, close_notify
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLException: Received fatal alert: close_notify
对我来说,看起来服务器甚至没有尝试回退到 TLSv1:一旦客户端声明 TLSv1.2 为首选,服务器就会退出。
相比之下,当我们在客户端中明确禁用 TLSv1.2 和 TLSv1.1,从而使 TLSv1 成为首选选项时,握手成功。
我们还尝试连接到另一个不知道 TLSv1.2 和 TLSv1.1 的旧服务器,但这里的连接按预期工作:即使客户端说它更喜欢 TLSv1.2,他们同意服务器使用 TLSv1,作为最佳通用协议:
main, WRITE: TLSv1.2 Handshake, length = 269
main, READ: TLSv1 Handshake, length = 85
...
问题:服务器是否有责任从客户端支持的 TLS/SSL 协议列表中进行选择?我可以对服务器维护人员说行为不端的是服务器,而不是我们的客户端吗?
客户端不提供支持的版本列表。客户端提供它可以提供的最佳版本,服务器应该回复服务器支持的最佳版本,该版本等于或低于客户端版本。如果客户端不愿意接受太低的版本,客户端将抛出错误并关闭连接。
我想你可以这么说。任何正确实现 TLS 1.0 的服务器都应该能够处理来自客户端的 TLS 1.2 连接,因为该协议是专门以这种方式设计的。不幸的是,仍然有足够多的损坏的 TLS 实现。