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

查看:143
本文介绍了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

推荐答案

Java中支持SSL套接字连接,对您来说可能是一个不错的选择。事先要理解的一件事是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 -dnamecn = 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 。替换你自己的名字和价值观。特别是,此命令会创建一个密钥对,该密钥对将在365242天(1000年)到期,对于IP地址为192.168.1.129的服务器。如果客户端将通过域名系统查找服务器,请使用类似 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.

现在,使用<导出服务器的证书code> 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.

最后,移动服务器。 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天全站免登陆