Java JSSE TLS - 此连接是否在两个方向上安全加密?

Sig*_*Seg 5 java ssl network-programming jsse

在Java中使用JSSE和TLS.我在服务器和客户端之间创建了一个安全套接字.在最终安全地连接套接字之后,我仍然有一个关于我现有代码安全性的基本问题.我按照教程中的说明进行操作,有时JavaDoc中的文档非常精确,但有点模糊,除非你说的是Swaheli方言的术语....

我现在已经在C++中进行了一段时间的网络编程.过渡到Java很容易.然而,最近我发现使交通安全是明智的.这是说:

我想以与Web浏览器创建安全套接字相同的方式创建安全套接字,因此双向流量都是加密的.客户端可以看到他们从服务器发送的个人帐户信息(如果被截获则非常糟糕),并且客户端可以安全地将他们的用户名和密码发送到服务器(如果被截获也非常糟糕).

我知道公钥加密的工作原理,但仅对公钥加密有副作用.您将公钥发送到客户端,客户端使用公钥加密,并将数据发送到服务器,只有服务器可以解密.根据我的理解,服务器使用私钥来加密发往客户端的消息,并且需要添加另一层安全性以防止任何拥有公钥的人能够解密它.

  1. 我有一个存储在public.key和private.key文件中的公钥/私钥对(我使用JSSE的keytool实用程序制作了这些对)
  2. 我在客户端中包含了public.key
  3. 我在服务器中包含了private.key

客户类:

    KeyStore keyStore;
    TrustManagerFactory tmf;
    KeyManagerFactory kmf;
    SSLContext sslContext;
    SecureRandom secureRandom = new SecureRandom();
    secureRandom.nextInt();

        keyStore = KeyStore.getInstance("JKS");
        keyStore.load(this.getClass().getClassLoader().getResourceAsStream("server.public"),"public".toCharArray());
        tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(keyStore);
        kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(keyStore, "public".toCharArray());
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), secureRandom);
        SSLSocketFactory sslsocketfactory = sslContext.getSocketFactory();
        SSLSocket sslsocket = (SSLSocket)sslsocketfactory.createSocket("localhost", 9999);
Run Code Online (Sandbox Code Playgroud)

服务器类:

    String passphrase = "secret"
    KeyStore keyStore;
    TrustManagerFactory tmf;
    KeyManagerFactory kmf;
    SSLContext sslContext;
    SecureRandom secureRandom = new SecureRandom();
    secureRandom.nextInt();

        keyStore = KeyStore.getInstance("JKS");
        keyStore.load(this.getClass().getClassLoader().getResourceAsStream("server.private"),passphrase.toCharArray());
        tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(keyStore);
        kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(keyStore, passphrase.toCharArray());
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), secureRandom);
        SSLServerSocketFactory sslserversocketfactory = sslContext.getServerSocketFactory();
        SSLServerSocket sslserversocket =
        (SSLServerSocket)sslserversocketfactory.createServerSocket(9999);
Run Code Online (Sandbox Code Playgroud)

/ *******问题******** /

一切正常!我将套接字连接到BufferedReader和BufferedWriter,并在accept()之后来回开始说话.从客户端连接并启动我的客户端和服务器发送/接收循环.

现在我知道,此时客户端到服务器的通信是安全的.只有服务器密钥才能解密来自客户端的流量.但是服务器到客户端的通信呢?客户端的密钥可以解密来自服务器的消息,但是在Public Key Crypto 101中,您了解到客户端现在应该向服务器发送公钥.这是在这个代码的幕后发生的吗?SSLContext是否解决了这个问题?或者现在我有从客户端到服务器的加密连接,我现在还希望为客户端生成私钥/公钥对吗?

如果上述代码中发送和接收的流量在两个方向上实际上都是安全的,请告诉我.

Bru*_*uno 6

SSL/TLS中的证书(及其私钥)仅用于验证SSL/TLS中的各方(通常,只有服务器使用证书).

实际加密是使用在握手期间协商的共享/对称密钥完成的,这些密钥是从使用经过身份验证的密钥交换形式交换的预主密钥派生的(参见TLS规范,第F.1.1节).

如何进行这种经过身份验证的密钥交换取决于密码套件,但最终结果是相同的:双方之间共享的预主密钥,保证只有客户端和服务器知道其证书的私钥.

在预主密钥交换之后,计算主密钥本身,从中导出一对密钥(如密钥计算部分所述):一个用于客户端写入(以及服务器读取)和一个供服务器编写(以及客户端读取).(还会生成MAC机密,以保证连接的完整性.)

原则上,并非所有密码套件都提供加密和经过身份验证的密钥交换(请参阅密码套件定义部分),但所有在JSSE中与SunJSSE提供程序一起启用的密钥套件都可以(请参阅SunJSSE提供程序文档中的密码套件).总之,不能够与密码套件anonNULL在他们的名字.

关于你的代码:

  • 有很多代码可以解决像这样的Key/TrustManagerFactory算法("SunX509").这通常是对Java 1.4默认值进行硬编码的代码.从Java 5开始,默认的TMF算法是PKIX(参见JSSE参考指南的Customization部分).解决这个问题的最佳方法是使用TrustManagerFactory.getDefaultAlgorithm()(对于KMF也是如此),这也将允许您的代码在不支持的其他JRE SunX509(例如IBM)上运行.

  • 由于您没有使用客户端证书身份验证,因此客户端没有任何意义KeyManagerFactory.你使用一个可能没有私钥的密钥库来初始化它,这使得它毫无意义.你也可以使用sslContext.init(null, tmf.getTrustManagers(), null).(对于两种情况下的安全随机,同样的事情,让JSSE使用其默认值.)


Vla*_*lad 1

您确实了解 PKI 的工作原理,但缺少 SSL 实现的两个关键部分。首先,大多数 PKI 算法允许双向加密流量。您可以使用公钥发送加密消息,只有拥有私钥的人才能读取它,这称为加密。您还可以使用私钥加密消息,任何拥有公钥的人都可以解密它,这称为数字签名。

另一个缺失的部分是 SSL 不使用 PKI 在客户端和服务器之间发送网络流量。它使用对称加密算法。然而,对称加密的密钥(称为会话密钥)是使用相当复杂的质询响应协议(采用 PKI 和证书)建立的。在此阶段,服务器向客户端证明它不是中间人,客户端可以选择向服务器证明其证书(如果有更强的身份验证),并建立对称会话密钥。更多详细信息请参见https://www.rfc-editor.org/rfc/rfc5246

对称密钥用于使用 RC5 或 AES 等算法加密流量