在不关闭底层套接字的情况下关闭SSL?

时间:2010-12-06 06:57:52

标签: java sockets ssl

如何在不关闭底层套接字的情况下优雅地关闭Java SSL会话?

场景是Java客户端连接到(非Java)服务器,设置SSL并安全地将凭证(用户名和密码)发送到服务器。服务器设置在这些凭据下运行的环境,在此环境中生成一个新进程并将套接字句柄传递给它,但问题是这个新进程无法重用现有的SSL连接(并且无法使用SSL会话)恢复)...所以我们的想法是在生成这个新进程之前关闭SSL,然后用新进程从头开始重新协商SSL会话。

问题是Java的SSLSocket's close()方法除了关闭SSL会话(sending the close_notify alert之外)之外还会关闭套接字。似乎没有相当于OpenSSL的SSL_shutdown()函数,它允许打开底层套接字。

我尝试了一些方法来解决这个问题:

  1. 第二次使用SSLSocket.startHandshake(),但会自动尝试恢复现有的缓存SSL会话(失败,因为生成的服务器进程不知道此会话),并且方法force resuming SSL sessions or die trying,没有方法可以使所有缓存的会话无效或禁止使用缓存的会话。

  2. 使用SSLSocketFactory.createSocket()在现有套接字的顶部创建SSLSocketautoClose设置为false。这并不会阻止close()方法关闭底层套接字,我怀疑autoClose参数只会阻止套接字在初始握手失败时被关闭。

  3. 在现有套接字上创建SSLSocket(如上所述),然后创建第二个SSLSocket以用于与生成的进程进行SSL握手(来自新的SSLContext )。这会失败,因为当服务器发送close_notify警报时(在生成子进程之前),Java会关闭套接字。

  4. 我听说过SSLEngine,但我也读过(尽管源代码目前没有我),使用它在TCP / IP上编写正确的SSL实现是一件非常痛苦的事情。如果我需要的是SSLSocket版本close()没有调用super.Close(),那就好像有点矫枉过正。

    但是,SSLSocket似乎甚至没有覆盖close()(根据javadoc),所以我不确定它是如何挂钩close()方法时看起来没有支持在Socket注册密切的听众。

    公司政策规定不能使用第三方加密库,因此我无法使用Bouncy Castle之类的替代SSL实施来解决问题。

    如果我们无法使当前的1插槽设计工作,另一种方法是重写客户端&amp;服务器使用2个独立的套接字(在必须反对拒绝服务和中间人攻击方面变得非常混乱,而不是SSL本来应该用于什么?)。< / p>

    对于解决这个问题的方法的任何意见或想法都是最受欢迎的。

2 个答案:

答案 0 :(得分:2)

  

这不会停止close()方法   从关闭底层套接字

是的。根据文档。

  

我怀疑autoClose   参数仅阻止套接字   从最初关闭时开始   握手失败。

没有。它可以防止关闭底层套接字。根据文档。

向我们展示一些代码。

答案 1 :(得分:2)

您应该能够使用普通的底层套接字(#3),因为这是带有Clear Control Channel的FTP的实现。

请记住,您尝试做的事情会让您在两个SSL会话之间进行中间人攻击,除非您在两者之间携带一些秘密来表明身份验证仍然有效。

  1. 使用网络顽皮(ARP中毒?)成为客户端和服务器之间的代理。
  2. 向两个方向转发数据包,直到身份验证完成并且SSL会话结束。 (任何SSL ALERT都会发出结束信号,我们不需要解密内容)。
  3. 关闭客户端的套接字,以免出错。
  4. 与服务器进行自己的SSL协商。
  5. 继续使用客户的凭据进行操作。