【问题标题】:Issue with Java SSLSocketJava SSLSocket 的问题
【发布时间】:2017-07-06 18:55:28
【问题描述】:

我目前正在开发一个客户端-服务器项目。
出于安全原因,我决定使用 SSL。

我尝试将所有 SocketServerSocket 对象转换为它们的 SSL 变体,但无济于事。
当我使用SSLServerSocket 并连接到它时,服务器端的套接字输出在outputstream.write(byte[]) 中间冻结。

这是我用来创建 SSL 套接字的函数, ContextController.CONTEXTSSLContextConstants.DEBUG 是我切换 SSL 的快捷方式:

public static ServerSocket server(int port, int backlog) throws IOException {
    return Constants.DEBUG ? new ServerSocket(port, backlog) : CONTEXT.getServerSocketFactory().createServerSocket(port, backlog);
}

public static Socket client(InetSocketAddress address) throws IOException {
    return Constants.DEBUG ? new Socket(address.getHostName(), address.getPort())
            : ContextController.CONTEXT.getSocketFactory().createSocket(address.getHostName(), address.getPort());
}

public static Socket client() throws IOException {
    return Constants.DEBUG ? new Socket() : ContextController.CONTEXT.getSocketFactory().createSocket();
}

Constants.DEBUG = true(即 SSL 关闭)时,它可以工作,但当 SSL 开启时,它会在无限期发送一些数据后冻结,如上所述。我该如何解决这个问题?

编辑
这里是ContextController.CONTEXT的来源:
(注意,我知道我应该使用实际的TrustManager,但首先我希望它能够工作)

    if (server) {// load the keystore
        try (FileInputStream fis = new FileInputStream(ks)) {
            CONTEXT = SSLContext.getInstance("SSL");

            // load the keystore from the file
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            keystore.load(fis, PASSWORD);

            // setup the KeyManagerFactory (used by the server)
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keystore, PASSWORD);

            CONTEXT.init(kmf.getKeyManagers(), null, null);
        }
        catch (Exception e) {
        }
    }
    else {
        CONTEXT = SSLContext.getInstance("SSL");
        CONTEXT.init(null, new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        } }, null);
    }

编辑 2
这是它冻结位置的堆栈跟踪,注意它没有崩溃,它挂起:

Thread [ClientExecThread #0] (Suspended)    
owns: AppOutputStream  (id=54)  
owns: ByteArrayOutputStream  (id=55)    
SocketOutputStream.socketWrite0(FileDescriptor, byte[], int, int) line: not available [native method]   
SocketOutputStream.socketWrite(byte[], int, int) line: 111  
SocketOutputStream.write(byte[], int, int) line: 155    
OutputRecord.writeBuffer(OutputStream, byte[], int, int, int) line: 431 
OutputRecord.write(OutputStream, boolean, ByteArrayOutputStream) line: 417  
SSLSocketImpl.writeRecordInternal(OutputRecord, boolean) line: 876  
SSLSocketImpl.writeRecord(OutputRecord, boolean) line: 847  
AppOutputStream.write(byte[], int, int) line: 123   
ByteArrayOutputStream.writeTo(OutputStream) line: 167   
SocketStream.streamPacket(Packet) line: 181 
ClientThread.lambda$8(Group) line: 150  
1427646530.run(Object) line: not available  
ClientThread.execute() line: 444    
ClientThread$ClientExecThread.run() line: 261

我在SocketStream.streamPacket(Packet) 181 之后的行放置了一个断点,但它永远不会到达它。

【问题讨论】:

  • 我们能看看 ContextController.CONTEXT 的样子吗?
  • 使用SSLContext.getInstance("TLS"); 而不是"SSL"。此外,在定义服务器时实现TrustManager。由于您没有提供任何错误,因此很难判断实际发生了什么。
  • 就是这个问题,没有错误。它只是冻结。
  • 同行是否在阅读?
  • Java SocketOutputStream 调用 OS TCP/IP 堆栈进行发送,如果发送缓冲区已满且接收方不接受(ACK-ing)数据,则会阻塞。

标签: java sockets ssl networking sslsocketfactory


【解决方案1】:

我真的不知道为什么会发生这种情况,而且我不需要 SSL 的所有方面(只有加密部分,这就是我没有实现 TrustManager 的原因)所以我决定改为实现 Diffie Hellman。

这按预期工作,并将 DH 与 AES 结合起来,我已根据我的要求加密流量。

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    • 2018-07-28
    • 2012-11-09
    • 1970-01-01
    相关资源
    最近更新 更多