SSLContext 和 SSLSocketFactory createSocket 线程安全吗?

Posted

技术标签:

【中文标题】SSLContext 和 SSLSocketFactory createSocket 线程安全吗?【英文标题】:Are SSLContext and SSLSocketFactory createSocket thread safe? 【发布时间】:2017-12-10 19:49:06 【问题描述】:

在我的测试中,我可以毫无问题地使用这两种方法,但是我找不到说明 SSLSocketFactory.createSocket() 是否是线程安全的文档。 是否可以在多个线程中使用相同的 SSLSocketFactory 来创建 SSL 套接字?

我的应用程序使用一个处理将纯文本套接字升级到 SSL 的类:

public class SSLHandler() 
    public Socket upgradeToSSL(Socket plainSocket) 
        SSLSocket sslContext = SSLContext.getInstance("TLS");
        TrustManager[] trustManager = new TrustManager[]
            new MyOwnTrustManager()
        ;

        sslContext.init(null, trustManager, null);
        SSLSocketFactory sslsocketfactory = sslContext.getSocketFactory();

        sslSocket = (SSLSocket) sslsocketfactory.createSocket(
                    remoteSocket,
                    remoteSocket.getInetAddress().getHostAddress(),
                    remoteSocket.getPort(),
                    true);

        return sslSocket;
    

SSLHandler 类用于多个线程,如下所示:

Socket plainSocket = new Socket(host, port);
//Do some stuff in plain text...

//Lets use TLS now
SSLHandler sslHandler = new SSLHandler();
sslHandler.upgradeToSSL(Socket plainSocket);

plainSocket = upgradeToSSL(plainSocket);

因此,为每个新线程创建一个 SSLHandler。为了避免这种情况,我正在考虑使用单例模式重构 SSLHandler:

public class SingletonSSLHandler() 
    private SSLSocket sslContext;
    private SSLSocketFactory sslSocketFactory;

    //GetInstance() and etc.

    private SingletonSSLHandler() 
        sslContext = SSLContext.getInstance("TLS");
        TrustManager[] trustManager = new TrustManager[]
            new MyOwnTrustManager()
        ;

        sslContext.init(null, trustManager, null);
        sslSocketFactory = sslContext.getSocketFactory();
    

    public static Socket upgradeToSSL(Socket plainSocket) 

        sslSocket = (SSLSocket) sslsocketfactory.createSocket(
                    remoteSocket,
                    remoteSocket.getInetAddress().getHostAddress(),
                    remoteSocket.getPort(),
                    true);

        return sslSocket;
    

【问题讨论】:

如果他们不是,那将是可怕的。除非只有一个 ssl 上下文,否则 Ssl 会话恢复将不起作用,并且鉴于这集中了所有 ssl 套接字创建事务,很可能没有争用(没有大的互斥锁),因此它必须是线程安全的。 【参考方案1】:

这个问题不能这么容易回答。原因是有实现,也有合约层面。

实施

SSLServerSocketFactory 类是抽象的,具有插件扩展机制。因此,从理论的角度来看,您无法确定自己的实现方式。

默认实现只是一个虚拟实现,由 JVM 选择的提供者的实现实例交换:

//
// The default factory does NOTHING.
//
class DefaultSSLServerSocketFactory extends SSLServerSocketFactory 
...

抽象类中有一些同步的迹象。 要回答 JDK 中的实现,需要针对每个操作系统(Windows、Linux、Mac OS)上的每个 JDK 版本分析问题。

关键部分(同步)的存在在您进入下一部分的合同级别时毫无意义。从我的角度来看,合同级别是本次讨论的重点。

合同

事实上,如果没有 API 文档保证/承诺它是线程安全的。所以,理论上它不是。您不能依赖任何没有 API 合同的东西。请阅读 this reference 给 Josh Blochs 的“黄金法则 70:记录线程安全”,了解关于依赖线程安全的假设的非常详细的讨论。

我可以使用上面提到的扩展机制编写一个非线程安全的 SSLServerSocketFactory 实现。缺乏线程安全不会是一个错误,因为它不是每个接口合同的强制要求。

总结

总而言之,API 并不能保证所有实现都是线程安全的。所以没有办法说会有一个(未来的)实现不是线程安全的。

【讨论】:

以上是关于SSLContext 和 SSLSocketFactory createSocket 线程安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

httpsUrlConnection 如何设置的默认sslcontext和 hostnameverifier?

httpsUrlConnection 如何设置的默认sslcontext和 hostnameverifier?

java SSLContext

Python中的Mongodb聚合:无法腌制'SSLContext'对象

使用 SSLContext 创建 SocketChannel

无法从外部证书创建 SSLContext