代码之家  ›  专栏  ›  技术社区  ›  hawkeye

为什么在Java中使用SSL服务器套接字连接块,而非SSL服务器套接字呢?

  •  0
  • hawkeye  · 技术社区  · 6 年前

    对于一个线程上的非SSL套接字服务器和客户端,请考虑以下代码:

    import java.io.DataInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class ServerClient {
        public static void main(String[] args) throws IOException {
            ServerSocket ss = new ServerSocket(0); // open a random free port.
    
            Socket c = new Socket(ss.getInetAddress(), ss.getLocalPort());
    
            Socket s = ss.accept();
    
            final byte[] bytes = "Hello World!".getBytes();
            final OutputStream out = c.getOutputStream();
            System.out.println("writing to stream");
            out.write(bytes.length);
            out.write(bytes);
    
            System.out.println("reading from stream");
    
            final DataInputStream in = new DataInputStream(s.getInputStream());
            int len = in.read();
            final byte[] b = new byte[len];
            in.readFully(b);
            System.out.println(new String(b));
    
            c.close();
            ss.close();
        }
    }
    

    这将产生以下输出:

    writing to stream
    reading from stream
    Hello World!
    

    此进程打开了一个服务器套接字-与客户端套接字连接。通过套接字传递数据,然后关闭。传递数据没有问题。

    考虑使用SSL套接字验证点的版本:

    import javax.net.ssl.SSLServerSocket;
    import javax.net.ssl.SSLServerSocketFactory;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    import java.io.DataInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.util.logging.Logger;
    
    public class SSLServerClient {
    
        private static Logger log = Logger.getLogger("InfoLogging");
    
        public static void main(String[] args) throws IOException {
    
            System.setProperty("javax.net.ssl.keyStore", "/path/KeyStore.jks");
            System.setProperty("javax.net.ssl.keyStorePassword", "password");
    
            SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
    
            SSLServerSocket serverListeningSSLSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(4380);
            log.info("Server started");
    
            SSLSocketFactory sslSocketFactory=(SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket clientSocket =  (SSLSocket) sslSocketFactory.createSocket(serverListeningSSLSocket.getInetAddress(),
                    serverListeningSSLSocket.getLocalPort());
    
            SSLSocket serverCommsSSLSocket = (SSLSocket) serverListeningSSLSocket.accept();
            log.info("new client");
    
            final byte[] bytes = "Hello World!".getBytes();
            final OutputStream out = clientSocket.getOutputStream();
            System.out.println("writing to stream");
            out.write(bytes.length);
            out.write(bytes);
    
            System.out.println("reading from stream");
    
            final DataInputStream in = new DataInputStream(serverCommsSSLSocket.getInputStream());
            int len = in.read();
            final byte[] b = new byte[len];
            in.readFully(b);
            System.out.println(new String(b));
    
            clientSocket.close();
            serverCommsSSLSocket.close();
            serverListeningSSLSocket.close();
        }
    }
    

    这将提供以下输出:

    Nov 21, 2018 10:23:51 PM com.gamble.ssl.SSLServerClient main INFO: Server started
    Nov 21, 2018 10:23:52 PM com.gamble.ssl.SSLServerClient main INFO: new client
    writing to stream
    

    也就是说,它阻止了服务器套接字的启动。

    我的问题是: 为什么在Java中使用SSL服务器套接字连接块,而非SSL服务器套接字呢?

    2 回复  |  直到 6 年前
        1
  •  0
  •   Stack Exchange Supports Israel    6 年前

    “翻转为纯文本”是什么?意思是?

    以下是您正在做的:

    • 创建SSL服务器套接字
    • 创建连接到SSL服务器套接字的普通套接字
    • 从客户端发送一些数据
    • 在服务器端读取一些数据

    现在,SSL套接字需要加密数据传输。但是,您不发送的数据没有加密,因此它不是有效的SSL,它抛出了一个异常——正如它所说,“无法识别的SSL消息”,因为您没有发送有效的SSL消息和“纯文本连接”?是一个可能有问题的提示。

    您必须在连接的两端使用SSL,否则它们无法正确地进行通信。

        2
  •  0
  •   hawkeye    6 年前

    这个问题的简单答案是:

    因为SSL握手 is asynchronous the non SSL socket 不必这么做。

    好的-原始SSL代码有两个问题:

    1. 没有信任库:

      System.setProperty( "javax.net.ssl.trustStore", "/path/KeyStore.jks");
      
    2. 因为握手是同步的-您必须在不同的线程上启动客户机。IE:

      (new Thread() {
        public void run() {
          // do stuff
        }
       }).start();
      

    所以代码看起来像:

        import javax.net.ssl.SSLServerSocket;
        import javax.net.ssl.SSLServerSocketFactory;
        import javax.net.ssl.SSLSocket;
        import javax.net.ssl.SSLSocketFactory;
        import java.io.DataInputStream;
        import java.io.IOException;
        import java.io.OutputStream;
        import java.util.logging.Logger;
    
        public class SSLServerClient {
    
            public static void main(String[] args) throws IOException {
    
                System.setProperty("javax.net.ssl.keyStore", "/path/KeyStore.jks");
                System.setProperty( "javax.net.ssl.trustStore", "/path/KeyStore.jks");
    
                System.setProperty("javax.net.ssl.keyStorePassword", "password");
    
                SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
    
                SSLServerSocket serverListeningSSLSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(4380);
                System.out.println("--server started");
    
                SSLSocketFactory sslSocketFactory=(SSLSocketFactory) SSLSocketFactory.getDefault();
                SSLSocket clientSocket =  (SSLSocket) sslSocketFactory.createSocket(serverListeningSSLSocket.getInetAddress(),
                        serverListeningSSLSocket.getLocalPort());
    
                SSLSocket serverCommsSSLSocket = (SSLSocket) serverListeningSSLSocket.accept();
                System.out.println("--new client");
    
                final byte[] bytes = "--Hello World!".getBytes();
                final OutputStream out = clientSocket.getOutputStream();
                System.out.println("--Gotten output stream");
                final DataInputStream in = new DataInputStream(serverCommsSSLSocket.getInputStream());
    
                (new Thread() {
                    public void run() {
                        System.out.println("--reading from stream");
    
                        int len = 0;
                        try {
                            len = in.read();
                            final byte[] b = new byte[len];
                            in.readFully(b);
                            System.out.println(new String(b));
    
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
    
    
                System.out.println("--writing to stream");
                out.write(bytes.length);
                System.out.println("--writing to stream - length");
                out.write(bytes);
    
                clientSocket.close();
                serverCommsSSLSocket.close();
                serverListeningSSLSocket.close();
            }
        }
    

    输出看起来像

        --server started
        --new client
        --Gotten output stream
        --writing to stream
        --reading from stream
        --writing to stream - length
        --Hello World!
    
        Process finished with exit code 0
    

    多恩

    (注意,我加了前导 -- 到在读取SSL调试输出时帮助的输出。