如何在不关闭底层套接字的情况下优雅地关闭Java SSL会话?
场景是Java客户端连接到(非Java)服务器,建立SSL并安全地向服务器发送凭据(用户名和密码)。服务器使用这些凭据设置在此环境下运行的环境,生成此环境中的新进程并将套接字句柄传递给它,但问题在于此新进程无法重用现有的SSL连接(也无法使用SSL会话恢复)...因此,想法是在生成此新进程之前关闭SSL,然后从头开始重新协商与新进程的SSL会话。
问题在于Java的SSLSocket's
但是,根据javadoc的描述,
公司政策规定不能使用第三方加密库,因此无法求助于类似Bouncy Castle这样的替代SSL实现来解决问题。
如果我们无法让当前的单套接字设计正常工作,那么替代方案是重写客户端和服务器以使用两个独立的套接字(这会在应对拒绝服务和中间人攻击方面变得非常混乱,这难道不是SSL在第一时间要解决的问题吗?)。
欢迎提供任何解决此问题的意见或想法。
场景是Java客户端连接到(非Java)服务器,建立SSL并安全地向服务器发送凭据(用户名和密码)。服务器使用这些凭据设置在此环境下运行的环境,生成此环境中的新进程并将套接字句柄传递给它,但问题在于此新进程无法重用现有的SSL连接(也无法使用SSL会话恢复)...因此,想法是在生成此新进程之前关闭SSL,然后从头开始重新协商与新进程的SSL会话。
问题在于Java的SSLSocket's
close()
方法除了关闭SSL会话(通过发送close_notify警报)外,还关闭套接字。似乎没有OpenSSL的SSL_shutdown()函数的等效函数,该函数允许保持底层套接字处于打开状态。
我已经尝试了几种方法来解决这个问题:
使用 SSLSocket.startHandshake() 第二次,但它会自动尝试恢复现有的缓存 SSL 会话(由于生成的服务器进程不知道此会话,因此失败),虽然有一种方法可以 强制恢复 SSL 会话或死亡尝试,但没有一种方法可以使所有缓存的会话无效或禁用使用缓存的会话。
使用 SSLSocketFactory.createSocket() 在现有套接字上创建一个
SSLSocket
,并将autoClose
设置为 false。这不会阻止close()
方法关闭基础套接字,我怀疑autoClose
参数仅在初始握手失败时防止套接字关闭。在现有套接字上创建一个
SSLSocket
(如上所述),然后创建第二个SSLSocket
与生成的进程进行 SSL 握手(来自新的 SSLContext)。这会失败,因为当服务器发送close_notify
警报(在生成子进程之前),Java 关闭套接字。
super.Close()
的SSLSocket
版本时,它似乎过度了。但是,根据javadoc的描述,
SSLSocket
甚至没有覆盖close()
,因此我不确定它如何钩住close()
方法,因为似乎没有支持在Socket
上注册关闭监听器的任何支持。公司政策规定不能使用第三方加密库,因此无法求助于类似Bouncy Castle这样的替代SSL实现来解决问题。
如果我们无法让当前的单套接字设计正常工作,那么替代方案是重写客户端和服务器以使用两个独立的套接字(这会在应对拒绝服务和中间人攻击方面变得非常混乱,这难道不是SSL在第一时间要解决的问题吗?)。
欢迎提供任何解决此问题的意见或想法。
Socket s = new Socket(HOST, PORT); SSLSocket ssl = ...; ssl.connect(s.getRemoteSocketAddress()); ...
?(至少对我来说,它不会关闭“底层”套接字.. 可能是我做错了什么 :) ) - dacwes
将不会被用于SSL通信。 - Caspar