java - 为什么 Java SSL 连接仍然对相同的客户端和服务器套接字使用相同的密码?

标签 java ssl encryption handshake

我听一位 friend 说:

For every SSL Connection in Java - when you look at the SSL debug - you can see the list of ciphers available during the handshake process, and that one is chosen.

我听另一个 friend 说:

For the same client and server SSL Sockets in Java - they will always choose the same cipher.

这对我来说似乎是不一致的。你怎么能用一系列密码握手并且每次仍然想出相同的密码?

所以我写了一些代码来测试它 - 似乎对于同一服务器和客户端的 1000 个连接 - 它总是选择相同的密码。为什么?

import javax.net.ssl.*;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

public class SSLServerClient {

    private static Set<String> cipherNames = new HashSet();

    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");


        for (int i = 0; i < 1000; i++) {


            SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();

            SSLServerSocket serverListeningSSLSocket = (SSLServerSocket) sslserversocketfactory.createServerSocket(4380);

            SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket clientSocket = (SSLSocket) sslSocketFactory.createSocket(serverListeningSSLSocket.getInetAddress(),
                    serverListeningSSLSocket.getLocalPort());

            SSLSocket serverCommsSSLSocket = (SSLSocket) serverListeningSSLSocket.accept();

            final byte[] bytes = "--Hello World!".getBytes();
            final OutputStream out = clientSocket.getOutputStream();


            final DataInputStream in = new DataInputStream(serverCommsSSLSocket.getInputStream());

            (new Thread() {
                public void run() {

                    int len = 0;
                    try {
                        len = in.read();
                        final byte[] b = new byte[len];
                        in.readFully(b);
                        //System.out.println(new String(b));

                    } catch (SSLException | EOFException | SocketException | NegativeArraySizeException  e) {
                        // skip this one
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();


            out.write(bytes.length);
            out.write(bytes);

            //System.out.println("protocol: "+ clientSocket.getSession().getProtocol());
            //System.out.println("cipher: " + clientSocket.getSession().getCipherSuite());
            cipherNames.add(clientSocket.getSession().getCipherSuite());

            clientSocket.close();
            serverCommsSSLSocket.close();
            serverListeningSSLSocket.close();
        }
        System.out.println("Ciphers used: " + cipherNames);
    }
}

输出是:

Ciphers used: [TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256]

即相同的密码 1000 次。

我的问题是:为什么 Java SSL 连接仍然对相同的客户端和服务器套接字使用相同的密码?

最佳答案

握手选择最佳可用密码,这取决于完全确定的算法。对于相同的输入(即双方声明可用的相同密码和版本以及考虑的任何其他因素),它将选择相同的密码。

假设选择是客观上最好的,随机选择另一个(即劣质)密码是没有意义的。事实上,这不是一个好主意。

在您的客户端中禁用 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(或提供更好的东西),您会得到其他东西。

关于java - 为什么 Java SSL 连接仍然对相同的客户端和服务器套接字使用相同的密码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53430336/

相关文章:

java - 将带有索引的属性列表转换为对象的 Xml

java - 如何使用 jetty 嵌入式 8.1.16.v20140903 设置 HTTPS

java - 加密数据库中数据的安全应用程序的体系结构

Java AWT 在半透明框架上绘制

java - 记录大字符串会导致 OutOfMemoryError

java - 概念差异 : Fully Abstract Class v. 接口(interface)

apache - 除了 CORS 预检外,所有请求都需要客户端证书

api - 适用于 Windows 的 cURL 无法与 Stack API 建立安全连接

php - 纯 PHP 中的 OpenPGP 加密

javascript - JavaScript 和 PHP 中不同的 AES 加密