Kyt*_*yte 8 java sockets ssl sslhandshakeexception sslsocketfactory
我正在加密服务器和客户端之间的TCP连接.在研究和测试过程中,我倾向于使用密钥加密.我的问题是我找不到任何有关如何实现此功能的教程.我发现的教程围绕一次性https请求,我只需要一个SSL Socket.
我到目前为止编写的代码如下.我几乎可以肯定它需要扩展,我只是不知道如何.任何帮助表示赞赏.
private ServerSocketFactory factory;
private SSLServerSocket serverSocket;
factory = SSLServerSocketFactory.getDefault();
serverSocket = (SSLServerSocket) factory.createServerSocket( <portNum> );
Run Code Online (Sandbox Code Playgroud)
用于接受客户端连接的服务器代码
SSLSocket socket = (SSLSocket) serverSocket.accept();
socket.startHandshake();
Run Code Online (Sandbox Code Playgroud)
我只是不知道如何实际握手.
参考:http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html
War*_*Dew 16
Java套接字连接在Java中得到很好的支持,对您来说可能是一个不错的选择.事先要理解的一件事是SSL提供加密和服务器身份验证; 你不能轻易得到加密.作为参考,加密可以防止网络窃听,而服务器身份验证可以防止"中间人"攻击,攻击者充当客户端和服务器之间的代理.
由于身份验证是SSL不可或缺的一部分,因此服务器需要提供SSL证书,客户端需要能够对证书进行身份验证.服务器将需要一个存储其证书的"密钥库"文件.客户端将需要一个"信任存储"文件,其中存储它所信任的证书,其中一个必须是服务器的证书,或者可以从中跟踪"信任链"到服务器证书的证书.
请注意,您无需了解SSL的详细信息即可使用Java SSL套接字.我认为阅读有关SSL如何工作的信息很有意思,例如在关于TLS的维基百科文章中,但复杂的多步骤握手和实际连接加密的设置都由SSLServerSocket和SSLSocket类负责处理.
代码
以上所有内容仅仅是解释以下一些代码的背景信息.该代码假设您熟悉常规的未加密套接字.在服务器上,您将需要这样的代码:
/**
* 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;
}
Run Code Online (Sandbox Code Playgroud)
然后可以像使用任何其他ServerSocket一样使用SSLServerSocket; 身份验证,加密和解密对调用代码完全透明.事实上,我自己的代码中的同源函数声明了一个普通的ServerSocket的返回类型,因此调用代码不会混淆.
注意:如果要将JRE的默认cacerts文件用作密钥库文件,则可以跳过创建SSLContext的行,并使用ServerSocketFactory.getDefault()获取ServerSocketFactory.您仍然必须将服务器的公钥/私钥对安装到密钥库文件中,在本例中为cacerts文件.
在客户端,您将需要这样的代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
与服务器代码中的SSLServerSocket一样,这里返回的SSLSocket就像普通的Socket一样使用; 进出SSLSocket的I/O使用未加密的数据完成,所有加密内容都在内部完成.
与服务器代码一样,如果要将默认JRE cacerts文件用作信任库,则可以跳过创建SSLContext并使用SSLSocketFactory.getDefault()而不是sslContext.getSocketFactory().在这种情况下,如果服务器的证书是自签名的,或者主要证书颁发机构之一未另行签发,则只需要安装服务器的证书.此外,为确保您不信任在您信任的证书链中合法颁发的证书,但要信任与您尝试访问的完全不同的域,您应该在该行之后添加以下(未经测试的)代码在哪里创建SSLSocket:
sslSocket.getSSLParameters().setEndpointIdentificationAlgorithm("HTTPS");
Run Code Online (Sandbox Code Playgroud)
如果您使用自己的信任库文件,但信任该文件中的一个或多个证书颁发机构颁发的所有证书,或者信任该文件中不同服务器的许多证书,这也适用.
证书,密钥库和信任库
现在是困难的,或者至少是稍微更难的部分:生成和安装证书.我建议使用Java keytool(最好是1.7或更高版本)来完成这项工作.
如果要创建自签名证书,请首先使用如下命令从命令行生成服务器的密钥对: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.替换你自己的名字和价值观.特别是,此命令会创建一个密钥对,该密钥对将在365242天(1000年)到期,对于IP地址为192.168.1.129的服务器.如果客户端将通过域名系统查找服务器,请使用类似san=dns:server.example.com的内容san=ip:192.168.1.129.有关keytool选项的更多信息,请使用man keytool.
系统将提示您输入密钥库的密码 - 或者设置密钥库的密码(如果这是新的密钥库文件),并设置新密钥对的密码.
现在,使用导出服务器的证书keytool -export -alias server -file server.cer -keystore server_key_store_file -rfc -v.这将创建一个server.cer包含服务器公钥的证书的文件.
最后,将server.cer文件移动到客户端计算机,并使用类似的方法将证书安装到客户端的信任存储区中keytool -import -alias server -file server.cer -keystore client_trust_store_file -v.系统将提示您输入信任库文件的密码; 提示将显示"输入密钥库密码",因为Java密钥工具适用于密钥存储文件和信任存储文件.请注意,如果您使用的是默认的JRE cacerts文件changeit,我相信初始密码是.
如果您使用从公认的认证机构购买的证书,并且您在cacerts客户端上使用默认的JRE 文件,则只需将证书安装在服务器的密钥库文件中; 你不必弄乱客户端的文件.服务器安装说明应由认证机构提供,或者您可以再次检查man keytool说明.
套接字有很多神秘感,特别是SSL套接字,但它们实际上非常容易使用.在许多情况下,十行代码将避免需要复杂和脆弱的消息传递或消息队列基础结构.考虑这个选项对你有好处.