SSL / TLS:服务器是否总是需要响应关闭通知?

信息安全 tls
2021-09-08 14:58:35

我是一名开发人员,我正在使用 SSL 实现套接字连接(使用javax.net.ssl.SSLEngine)。为了进行测试,我正在打开与 Internet 上任意 HTTPS 服务器的连接,以查看在打开连接之后和关闭连接之前握手过程如何进行。

我的问题是关于关闭连接之前的握手。

我的应用程序向服务器发送 SSL 关闭通知警报,SSLEngine然后 Java 期望从服务器收到关闭通知警报。但是,某些服务器不会将关闭通知发送回我的应用程序 - 它们只是关闭连接。

例如,https: //www.oracle.com 按我的预期发送关闭通知,但https://www.google.com没有 - 它只是在我的应用程序发送关闭通知后关闭连接。

服务器是否可以选择响应客户端的关闭通知?如果服务器不这样做,它对我的​​应用程序有什么后果?(如果服务器不这样做,我可以安全地忽略它吗?)。

(Github 上的示例代码:jesperdj/sslclient

2个回答

关闭通知应由客户端和服务器根据规范发送。

RFC 2246 部分

客户端和服务器必须共享连接即将结束的知识,以避免截断攻击。任何一方都可以
发起结束消息的交换。

close_notify 此消息通知收件人,发件人将不再在此连接上发送任何消息。请注意,从 TLS 1.1 开始,无法正确关闭连接不再需要不恢复会话。 这是对 TLS 1.0 的更改,以符合广泛的实施实践。

任何一方都可以通过发送 close_notify 警报来启动关闭。关闭警报后收到的任何数据都将被忽略。

现在,并非所有实现都遵循规范。每个人都震惊了……我知道。看看那句话的粗体部分。他们在 1.1 中更改了规范,因为广泛的实现不发送close_notify消息。

为确保您的应用程序进行尽职调查,您应始终发送close_notify. 对您来说重要的是忽略发送给您的任何其他数据,除了close_notify. 就你而言,连接已经结束。很高兴从服务器听到这个消息,但您需要做的就是删除隧道中的任何其他数据。

如上面引用所述,在 TLS 1.1 中,即使一方不执行close_notify.

这确实意味着您容易受到截断攻击:

截断攻击

TLS 截断攻击会阻止受害者的帐户注销请求,以便用户在不知不觉中保持登录到 Web 服务。当发送退出请求时,攻击者会注入一个未加密的 TCP FIN 消息(不再有来自发送者的数据)来关闭连接。因此,服务器不会收到注销请求,也不知道异常终止。

这是大多数金融网站在会话过期或超时时将您注销的一个很好的原因。

要完成@raz'的回答,有几点:

OpenSSL以及因此基于 OpenSSL(客户端和服务器)的实现往往不再发送close_notify消息;他们只是断开连接。主要原因是在现有的 Web 服务器和客户端中,连接是在一个池中管理的,该池会在一些不活动延迟后关闭它们;该池管理低级套接字,并且不知道 SSL 可能是什么;因此,SSL 层无法发送(或等待)显式close_notify.

这种设计的一个根本原因是避免过度保留资源。从服务器的角度来看,不活动的客户端可能是死客户端——可能是客户端计算机崩溃或或多或少干净地关闭,或者它的网络访问刚刚中断。因此,可能没有人接收close_notify. 通常情况下,TCP 连接是缓冲的,因此服务器代码可以close_notify立即发送并关闭连接,而无需等待来自客户端的 ACK(ACK 永远不会到来,客户端已经死亡)。但是,客户端死亡可能在任何时候发生,包括在从服务器发送上一个应答的过程中,因此此时 TCP 缓冲区可能已满。因此,发送close_notify 可能会停顿很长时间,直到 TCP 层确定连接真的死了(这可能需要几个小时)。

通过简单地直接关闭套接字,在一些固定的不活动延迟之后,无论当时的连接逻辑状态如何(SSL 与否;发送答案或等待下一个请求),服务器确保它们避免阻塞资源以受益于死客户端.

HTTPS 级别的主要“截断攻击”与 HTTP 0.9 有关。在 HTTP 0.9 中,每个请求都使用一个新连接,并且服务器会在没有显式数据终止的情况下发回答案;当服务器完成发送数据时,它会关闭底层套接字。客户端因此知道它在套接字关闭时获得了所有数据。

对于 HTTP 0.9,缺少 aclose_notify意味着攻击者可以截断答案(通过强制 TCP 级别关闭)并且客户端不会知道它。这被认为是 SSL 2.0 的主要弱点之一。

但是,为每个请求打开一个新连接的效率非常低,因此从 HTTP 1.0 开始,客户端和服务器会为多个请求和响应重用连接。这反过来又要求 HTTP 协议自终止:仅检查交换的字节就足以决定是否到达请求或应答的结尾,而不依赖于来自传输介质的“关闭”事件。基本上,客户端和服务器使用显式Content-Length标头,或者(对于数据流)使用“分块传输编码”。当进入 SSL/TLS 隧道的应用程序协议自行终止时,close_notify是多余的,可以省略。这正是现代 HTTPS 中发生的情况。现代服务器不再使用 HTTP 0.9;他们所有的回应都是自我终止的;所以他们有能力(从安全的角度)不发送close_notify.

@raz 谈到的截断攻击更高一级:客户端发送一个 HTTP 请求以执行某些“注销”操作,但不等待相应的答案(一个HTTP答案,而不是 a close_notify)。存在或缺少 aclose_notify在这里不会改变任何东西;弱点是不耐烦的用户。

SSL/TLS 会话重用实际上比单纯的恢复更大。最初,SSL 的设计理念是客户端打开一个与服务器的连接,如果前一个连接关闭,则只需打开一个新连接。

Web 浏览器不再那样做。相反,他们打开了几个到服务器的连接,主要是为了他们可以并行发送请求,以获得更好的用户体验。HTTP-1.0 参考

   Clients that use persistent connections SHOULD limit the number of
   simultaneous connections that they maintain to a given server. A
   single-user client SHOULD NOT maintain more than 2 connections with
   any server or proxy.

然而,实践和往常一样,有点不同(不过,一些浏览器对同时连接的数量应用不同的限制,具体取决于连接是否使用 SSL)。

对于所有这些连接,典型的浏览器将与一个连接进行完整的握手,然后为其他连接“恢复”该会话,即使“会话”仍处于活动状态并启动第一个连接。因此,会话可以在停止之前恢复。@raz 引用的 TLS 1.0 中的规定只是扩展了这个想法,因为它定义了会话可以恢复,而不管其他连接上的同一会话发生了什么或仍然发生什么。实际上,会话恢复不再是恢复,而是重用会话参数(即协商的共享密钥)。

总结: SSL/TLS 正式提供了加密保护的闭包:当一个连接被关闭时,客户端和服务器都可以保证这个闭包是真实的,并且不会被插入的攻击者注入。现有实践偏离了该理论,并且实现不再提供该保证。

这对于 HTTPS Web 服务器来说不是问题,因为此类服务器强制使用不需要闭包加密保护的自终止应用程序协议(具有显式块或内容长度的 HTTP 1.0+)。

总的来说,不发送 aclose_notify是协议的弱化,如果(且仅当)底层协议没有自行终止时,可能会利用它。幸运的是,非自终止协议极为罕见,可以说是“设计不佳”(如果只是因为它们不允许连接重用),因此这种弱化在实践中并不是一个大问题(暂时。 ..)。