如何在不关闭底层套接字的情况下优雅地关闭Java SSL会话?
场景是Java客户端连接到(非Java)服务器,设置SSL并安全地将凭证(用户名和密码)发送到服务器。服务器设置在这些凭据下运行的环境,在此环境中生成一个新进程并将套接字句柄传递给它,但问题是这个新进程无法重用现有的SSL连接(并且无法使用SSL会话)恢复)...所以我们的想法是在生成这个新进程之前关闭SSL,然后用新进程从头开始重新协商SSL会话。
问题是Java的SSLSocket's close()
方法除了关闭SSL会话(sending the close_notify alert之外)之外还会关闭套接字。似乎没有相当于OpenSSL的SSL_shutdown()函数,它允许打开底层套接字。
我尝试了一些方法来解决这个问题:
第二次使用SSLSocket.startHandshake(),但会自动尝试恢复现有的缓存SSL会话(失败,因为生成的服务器进程不知道此会话),并且方法force resuming SSL sessions or die trying,没有方法可以使所有缓存的会话无效或禁止使用缓存的会话。
使用SSLSocketFactory.createSocket()在现有套接字的顶部创建SSLSocket
,autoClose
设置为false。这并不会阻止close()
方法关闭底层套接字,我怀疑autoClose
参数只会阻止套接字在初始握手失败时被关闭。
在现有套接字上创建SSLSocket
(如上所述),然后创建第二个SSLSocket
以用于与生成的进程进行SSL握手(来自新的SSLContext )。这会失败,因为当服务器发送close_notify
警报时(在生成子进程之前),Java会关闭套接字。
我听说过SSLEngine,但我也读过(尽管源代码目前没有我),使用它在TCP / IP上编写正确的SSL实现是一件非常痛苦的事情。如果我需要的是SSLSocket
版本close()
没有调用super.Close()
,那就好像有点矫枉过正。
但是,SSLSocket
似乎甚至没有覆盖close()
(根据javadoc),所以我不确定它是如何挂钩close()
方法时看起来没有支持在Socket
注册密切的听众。
公司政策规定不能使用第三方加密库,因此我无法使用Bouncy Castle之类的替代SSL实施来解决问题。
如果我们无法使当前的1插槽设计工作,另一种方法是重写客户端&amp;服务器使用2个独立的套接字(在必须反对拒绝服务和中间人攻击方面变得非常混乱,而不是SSL本来应该用于什么?)。< / p>
对于解决这个问题的方法的任何意见或想法都是最受欢迎的。
答案 0 :(得分:2)
这不会停止close()方法 从关闭底层套接字
是的。根据文档。
我怀疑autoClose 参数仅阻止套接字 从最初关闭时开始 握手失败。
没有。它可以防止关闭底层套接字。根据文档。
向我们展示一些代码。
答案 1 :(得分:2)
您应该能够使用普通的底层套接字(#3),因为这是带有Clear Control Channel的FTP的实现。
请记住,您尝试做的事情会让您在两个SSL会话之间进行中间人攻击,除非您在两者之间携带一些秘密来表明身份验证仍然有效。