这是我最初的(暂时删除的)答案,但是显然还不够好,因为它很快就被-2了……我想我应该添加更多的解释。
不能关闭SSL /
TLS套接字的一半连接,以使其符合TLS协议(如关闭警报部分所述)。
客户端和服务器必须共享有关连接即将结束的知识,以避免被截断攻击。任何一方均可发起结束消息的交换。
close_notify此消息通知收件人,发件人将不再通过此连接发送任何消息。如果在没有适当的close_notify消息的情况下终止任何连接,并且会话级别等于警告,则该会话将无法恢复。任何一方都可以通过发送close_notify警报来发起关闭。关闭警报后收到的任何数据都将被忽略。
要求各方在关闭连接的写端之前发送close_notify警报。要求另一方以自己的close_notify警报响应并立即关闭连接,并丢弃所有未决的写入。关闭的发起方不需要在关闭连接的读取端之前等待响应的close_notify警报。
尽管您可能只想关闭一半的连接(通过
shutdownInput()/
输入或输出
shutdownOutput()),但底层TLS层仍需要
close_notify在真正关闭通信之前发送此数据包,否则,它将被视为截断攻击。
修复非常简单:仅
close()在
SSLSockets上使用:它不仅会像普通TCP套接字那样关闭连接,而且会根据SSL / TLS规范进行整洁的连接。
编辑 : 附加说明 。
简短的答案仍然是:use
close(),您可能还需要从SSL / TLS顶部的协议中找出合适的时机。
(为澄清起见,您实际上想做的是有效的“中间人”(MITM)代理。您需要将客户端配置为信任代理的证书,就像它是服务器一样证书(如果要透明地进行的话)。HTTPS连接如何通过HTTP代理工作是一个不同的问题。)
在您对其他相关问题的一些评论中,我得到的印象是,您认为不返回
-1就是“破坏了TLS协议”。这实际上与协议无关,而是与API有关:将编程结构(类,方法,函数等)提供给TLS堆栈的(程序员)用户以使用TLS的方式。
SSLSocketAPI只是API的一部分,以使程序员能够以类似于plain的方式使用SSL
/ TLS
Socket。TLS规范根本不涉及套接字。TLS(及其前身,SSL)的构建旨在提供这种抽象,但归根结底
SSLSocket就是:抽象。符合OOP设计原则,
SSLSocket继承
Socket并尝试尽可能地坚持行为
Socket。但是,由于SSL
/ TLS的工作方式(并且
SSLSocket有效地位于normal之上
Socket),因此无法精确映射所有功能。
特别是,从普通TCP套接字到SSL /
TLS套接字的过渡区域不能完全透明地建模。在设计
SSLSocket类时,必须做出一些任意选择(例如,握手方式):这是在(a)不向
SSLSocket用户暴露过多的TLS特殊性,(b)使TLS机制起作用和((
c)将所有这些映射到超类(
Socket)提供的现有接口。这些选择不可避免地会对的功能产生一些影响
SSLSocket,这就是其Javadoc
API页面包含相对大量文本的原因。
SSLSocket.close()就API而言,必须遵守的描述
Socket.close()。在
InputStream/
OutputStream从所获得的
SSLSocket不同于底层平原的
Socket那个(除非您已将其显式转换),否则可能看不到。
SSLSocket被设计为尽可能地像平原一样可用
Socket,并且
InputStream您获得的设计被设计为与基于文件的输入流尽可能接近。顺便说一下,这不是特定于Java的。甚至C语言中的Unix套接字也与文件描述符和一起使用
read()。只要您知道它们的局限性,这些抽象就很方便并且在大多数时候都可以使用。
当涉及到时
read(),即使在C语言中,的概念也
EOF来自文件结尾终止,但实际上并没有处理文件。TCP套接字的问题在于,虽然您可以检测到远程方在发送时选择了关闭连接,但是
FIN您却无法检测到它没有发送任何内容(如果没有发送)。从套接字读取任何内容时,无法分辨无效连接和断开连接之间的区别。因此,在进行网络编程时,只能依靠
-1从
InputStreamif
读取,但您绝不能完全依靠它来进行读取,否则最终可能会遇到未发布的无效连接。一方正确地关闭半个TCP连接是“礼貌”的(例如,远程方读取
-1其
InputStream或类似的内容(如Java中的有序与异常连接发行版中所述),仅处理这种情况是不够的。这就是为什么TCP之上的协议通常旨在指示何时完成发送数据的原因:例如,SMTP发送
QUIT(并具有特定的终止符),HTTP 1.1使用
Content-Length或分块编码。
(顺便说一句,如果您对提供的抽象不满意
SSLSocket,请尝试
SSLEngine直接使用。它可能会更难,并且不会改变TLS规范中关于发送的说明
close_notify。)
通常,对于TCP,您应该在应用协议级别上知道何时停止发送和接收数据(以避免未释放的连接和/或依赖超时错误)。TLS规范中的这句话使TLS成为一个更好的要求,它是对TLS的一个更强的要求:“
要求对方以自己的close_notify警报响应并关闭连接,并立即丢弃所有未决的写入。
”必须通过应用程序协议以某种方式进行同步,否则远程方可能仍然需要写一些东西(尤其是如果您允许使用流水线式的请求/响应)。
如果您要编写的代理用于拦截HTTPS连接(作为MITM),则可以调查请求的内容。即使HTTP请求是通过管道传递的,您也可以计算目标服务器发送的响应数(并通过Content-
Length或块定界符期望它们何时结束)。
但是,您将无法拥有一个完全透明的通用TLS“拦截器”。TLS旨在确保两方之间的传输安全,并且中间没有一方。虽然大多数实现该保护的机制(避免使用MITM)都是通过服务器证书来完成的,但其他一些TLS机制也会成为障碍(关闭警报就是其中之一)。请记住,您实际上是在创建两个不同的TLS连接,考虑到TLS的目的,它们很难合并为一个事实,这不足为奇。
SSLSocket.close()是关闭的正确方法
SSLSocket,但是应用程序协议也将帮助您确定何时合适。



