Java 中的密钥 SSL 套接字连接 [英] Secret Key SSL Socket connections in Java

查看:39
本文介绍了Java 中的密钥 SSL 套接字连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在对服务器和客户端之间的 tcp 连接进行加密.在研究和测试过程中,我倾向于使用密钥加密.我的问题是我找不到有关如何实现此功能的任何教程.我发现的教程都是围绕一次性 https 请求展开的,我只需要一个 SSL 套接字.

I'm working on encrypting a tcp connection between a server and a client. In the course of research and testing I'm leaning towards using secret key encryption. My problem is that I cannot find any tutorials on how to implement this feature. The tutorials I have found revolve around one-shot https requests, all I need is a SSL Socket.

我目前编写的代码如下.我几乎可以肯定它需要扩展,我只是不知道如何.任何帮助表示赞赏.

The code I've written so far is below. I'm almost certain that it needs to be extended, I just don't know how. Any help is appreciated.

private ServerSocketFactory factory;
private SSLServerSocket serverSocket;

factory = SSLServerSocketFactory.getDefault();
serverSocket = (SSLServerSocket) factory.createServerSocket( <portNum> );

用于接受客户端连接的服务器代码

Server code for accepting client connections

SSLSocket socket = (SSLSocket) serverSocket.accept();
socket.startHandshake();

我只是不知道如何实际进行握手.

I just don't know how to actually do the handshake.

参考:http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html

推荐答案

SSL 套接字连接在 Java 中得到了很好的支持,很可能是您的不错选择.需要提前了解的一件事是 SSL 提供加密和服务器身份验证;你不能轻易获得加密.作为参考,加密可以防止网络窃听,而服务器身份验证可以防止中间人"攻击,其中攻击者充当客户端和服务器之间的代理.

SSL socket connections are well supported in Java and are likely a good choice for you. The one thing to understand in advance is that SSL provides both encryption and server authentication; you can't easily get just the encryption. For reference, the encryption protects against network eavesdropping, while the server authentication protects against "man in the middle" attacks, where the attacker acts as a proxy between the client and the server.

由于身份验证是 SSL 的一个组成部分,因此服务器需要提供 SSL 证书,并且客户端需要能够对证书进行身份验证.服务器将需要一个密钥库"文件来存储其证书.客户端将需要一个信任库"文件,用于存储它信任的证书,其中之一必须是服务器的证书,或者是可以从信任链"追溯到服务器证书的证书.

Since authentication is an integral part of SSL, the server will need to provide an SSL certificate, and the client will need to be able to authenticate the certificate. The server will need a "key store" file where its certificate is stored. The client will need a "trust store" file where it stores the certificates it trusts, one of which must either be the server's certificate, or a certificate from which a "chain of trust" can be traced to the server's certificate.

请注意,为了使用 Java SSL 套接字,您无需了解 SSL 的来龙去脉.我确实认为通读有关 SSL 如何工作的信息很有趣,例如在关于 TLS 的维基百科文章中,但是复杂的多步握手和实际连接加密的设置都是由 SSLServerSocket 和 SSLSocket 类在幕后处理的.

Note that you do not have to know anything about the ins and outs of SSL in order to use Java SSL sockets. I do think it is interesting to read through information on how SSL works, for example in the Wikipedia article on TLS, but the complicated multistep handshake and the setup of the actual connection encryption is all handled under the covers by the SSLServerSocket and SSLSocket classes.

代码

以上所有只是解释以下代码的背景信息.该代码假定您熟悉常规的未加密套接字.在服务器上,您将需要这样的代码:

All of the above is just background information to explain some of the following code. The code assumes some familiarity with regular, unencrypted sockets. On the server, you will need code like this:

/**
 * Returns an SSLServerSocket that uses the specified key store file 
 * with the specified password, and listens on the specified port.
 */
ServerSocket getSSLServerSocket(
    File keyStoreFile, 
    char[] keyStoreFilePassword,
    int port
) throws GeneralSecurityException, IOException {
    SSLContext sslContext 
        = SSLConnections.getSSLContext(keyStoreFile, keyStoreFilePassword);
    SSLServerSocketFactory sslServerSocketFactory 
        = sslContext.getServerSocketFactory();
    SSLServerSocket sslServerSocket
        = (SSLServerSocket) sslServerSocketFactory.createServerSocket(port);
    return sslServerSocket;
}

然后可以像使用任何其他 ServerSocket 一样使用 SSLServerSocket;认证、加密和解密对调用代码是完全透明的.事实上,我自己代码中的同源函数声明了一个简单的ServerSocket的返回类型,所以调用代码不会混淆.

The SSLServerSocket can then be used exactly like you would use any other ServerSocket; the authentication, encryption and decryption will be completely transparent to the calling code. In fact, the cognate function in my own code declares a return type of just plain ServerSocket, so the calling code can't get confused.

注意:如果您想使用 JRE 的默认 cacerts 文件作为您的密钥存储文件,您可以跳过创建 SSLContext 的行,并使用 ServerSocketFactory.getDefault() 获取 ServerSocketFactory.您仍然需要将服务器的公钥/私钥对安装到密钥存储文件中,在本例中为 cacerts 文件.

Note: if you want to use the JRE's default cacerts file as your key store file, you can skip the line creating the SSLContext, and use ServerSocketFactory.getDefault() to get the ServerSocketFactory. You will still have to install the server's public/private key pair into the key store file, in this case the cacerts file.

在客户端,你需要这样的代码:

On the client, you will need code like this:

SSLSocket getSSLSocket(
    File trustStoreFile,
    char[] trustStoreFilePassword,
    InetAddress serverAddress,
    port serverPort
) throws GeneralSecurityException, IOException {
    SSLContext sslContext 
        = SSLConnections.getSSLContext(trustStoreFile, trustStoreFilePassword);
    SSLSocket sslSocket 
        = (SSLSocket) sslContext.getSocketFactory().createSocket
            (serverAddress, serverPort);
    sslSocket.startHandshake();
    return sslSocket;
}

和服务器代码中的SSLServerSocket一样,这里返回的SSLSocket就像普通的Socket一样使用;进出 SSLSocket 的 I/O 是使用未加密的数据完成的,所有加密的东西都在内部完成.

As in the case of the SSLServerSocket in the server code, the returned SSLSocket here is used just like a regular Socket; I/O into and out of the SSLSocket is done with unencrypted data, and all the cryptographic stuff is done inside.

与服务器代码一样,如果您想使用默认的 JRE cacerts 文件作为您的信任存储,您可以跳过 SSLContext 的创建并使用 SSLSocketFactory.getDefault() 而不是 sslContext.getSocketFactory().在这种情况下,如果服务器的证书是自签名的或不是由主要认证机构之一颁发的,则您只需要安装服务器的证书.此外,为了确保您不信任在您信任的证书链中合法颁发的证书,而是信任与您尝试访问的域完全不同的域,您应该在该行之后添加以下(未经测试的)代码在其中创建 SSLSocket:

As with the server code, if you want to use the default JRE cacerts file as your trust store, you can skip creation of the SSLContext and use SSLSocketFactory.getDefault() instead of sslContext.getSocketFactory(). In this case, you will only need to install the server's certificate if the server's certificate was self signed or not otherwise issued by one of the major certificating authorities. In addition, to ensure you aren't trusting a certificate that is legitimately issued within a certificate chain you trust, but to an entirely different domain than you are trying to get to, you should add the following (untested) code just after the line where you create the SSLSocket:

    sslSocket.getSSLParameters().setEndpointIdentificationAlgorithm("HTTPS");

如果您使用自己的信任存储文件,但信任该文件中一个或多个认证机构颁发的所有证书,或者信任该文件中不同服务器的多个证书,则这也适用.

This would also apply if you are using your own trust store file, but trusting all certificates issued by one or more certificating authorities in that file, or trusting a number of certificates for different servers in that file.

证书、密钥库和信任库

现在是困难的部分,或者至少是稍微困难的部分:生成和安装证书.我建议使用 Java keytool,最好是 1.7 或更高版本来完成这项工作.

Now for the hard, or at least, slightly harder part: generating and installing the certificates. I recommend using the Java keytool, preferably version 1.7 or above, to do this work.

如果您要创建自签名证书,请首先使用如下命令从命令行生成服务器的密钥对:keytool -genkey -alias server -keyalg rsa -dname "cn=server, ou=unit, o=org, l=City, s=ST, c=US" -validity 365242 -keystore server_key_store_file -ext san=ip:192.168.1.129 -v.替换您自己的名称和值.特别是,此命令会为 IP 地址为 192.168.1.129 的服务器创建一个在 365242 天(1000 年)后到期的密钥对.如果客户端将通过域名系统查找服务器,请使用类似 san=dns:server.example.com 的内容而不是 san=ip:192.168.1.129.有关 keytool 选项的更多信息,请使用 man keytool.

If you are creating a self signed certificate, first generate the server's keypair from the command line with a command like the following: keytool -genkey -alias server -keyalg rsa -dname "cn=server, ou=unit, o=org, l=City, s=ST, c=US" -validity 365242 -keystore server_key_store_file -ext san=ip:192.168.1.129 -v. Substitute your own names and values. In particular, this command creates a key pair that expires in 365242 days - 1000 years - for a server that will be at IP address 192.168.1.129. If the clients will be finding the server through the domain name system, use something like san=dns:server.example.com instead of san=ip:192.168.1.129. For more information on keytool options, use man keytool.

系统将提示您输入密钥库的密码 - 或者设置密钥库的密码,如果这是一个新的密钥库文件 - 并为新的密钥对设置密码.

You will be prompted for the key store's password - or to set the key store's password, if this is a new key store file - and to set the password for the new key pair.

现在,使用keytool -export -alias server -file server.cer -keystore server_key_store_file -rfc -v 导出服务器的证书.这将创建一个 server.cer 文件,其中包含带有服务器公钥的证书.

Now, export the server's certificate using keytool -export -alias server -file server.cer -keystore server_key_store_file -rfc -v. This creates a server.cer file containing the certificate with the server's public key.

最后,将 server.cer 文件移动到客户端机器并将证书安装到客户端的信任库中,使用类似keytool -import -alias server -file server.cer -keystore client_trust_store_file -v.系统将提示您输入信任存储文件的密码;提示将显示输入密钥库密码",因为 Java 密钥工具可用于密钥库文件和信任库文件.请注意,如果您使用的是默认的 JRE cacerts 文件,我相信初始密码是 changeit.

Finally, move the server.cer file to the client machine and install the certificate into the client's trust store, using something like, keytool -import -alias server -file server.cer -keystore client_trust_store_file -v. You will be prompted for the password to the trust store file; the prompt will say "Enter keystore password", since the Java keytool works with both key store files and trust store files. Note that if you are using the default JRE cacerts file, the initial password is changeit, I believe.

如果您使用的是从公认的认证机构购买的证书,并且您使用的是客户端上的默认 JRE cacerts 文件,则只需将证书安装在服务器的密钥库中文件;您不必弄乱客户的文件.服务器安装说明应由认证机构提供,或者您可以再次查看man keytool 以获取说明.

If you are using a certificate purchased from a generally recognized certificating authority, and you're using the default JRE cacerts file on the client, you only have to install the certificate in the server's key store file; you don't have to mess with the client's files. Server installation instructions should be provided by the certificating authority, or again you can check man keytool for instructions.

关于套接字,尤其是 SSL 套接字有很多神秘之处,但它们实际上很容易使用.在许多情况下,十行代码将避免需要复杂和脆弱的消息传递或消息队列基础设施.考虑这个选项对你有好处.

There's a tremendous amount of mystique surrounding sockets and, especially, SSL sockets, but they're actually quite easy to use. In many cases, ten lines of code will avoid the need for complex and fragile messaging or message queueing infrastructure. Good for you for considering this option.

这篇关于Java 中的密钥 SSL 套接字连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆