安全是一个复杂的话题。在本节中,我们将演示该主题的几个简单方面,因为它与网络有关。具体来说,我们将创建一个安全的回显服务器。创建安全回显服务器与我们之前开发的非安全回显服务器没有太大区别。然而,在幕后有很多事情要让它发挥作用。我们可以忽略许多这些细节现在,但我们会更深入地钻研它在第8章,网络安全。
我们将使用该类来实例化安全服务器套接字。此外,有必要创建底层 SSL 机制可用于加密通信的密钥。 SSLServerSocketFactory
SSLServerSocket
在以下示例中声明了一个类作为回显服务器。由于它与前面的回显服务器类似,我们将不解释它的实现,除了它与SSLServerSocketFactory
类的使用的关系。其静态getDefault
方法返回 的实例ServerSocketFactory
。它的createServerSocket
方法返回一个ServerSocket
绑定到8000
能够支持安全通信的端口的实例。否则,它的组织和功能类似于以前的回显服务器:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLServerSocketFactory;
public class SSLServerSocket {
public static void main(String[] args) {
try {
SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket serverSocket = ssf.createServerSocket(8000);
System.out.println("SSLServerSocket Started");
try (Socket socket = serverSocket.accept();
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
System.out.println("Client socket created");
String line = null;
while (((line = br.readLine()) != null)) {
System.out.println(line);
out.println(line);
}
br.close();
System.out.println("SSLServerSocket Terminated");
} catch (IOException ex) {
// Handle exceptions
}
} catch (IOException ex) {
// Handle exceptions
}
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import javax.net.ssl.SSLSocketFactory;
public class SSLClientSocket {
public static void main(String[] args) throws Exception {
System.out.println("SSLClientSocket Started");
SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
try (Socket socket = sf.createSocket("localhost", 8000);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Enter text: ");
String inputLine = scanner.nextLine();
if ("quit".equalsIgnoreCase(inputLine)) {
break;
}
out.println(inputLine);
System.out.println("Server response: " + br.readLine());
}
System.out.println("SSLServerSocket Terminated");
}
}
}
如果我们在客户端之后执行此服务器,它们将因连接错误而中止。这是因为我们没有提供一组应用程序可以共享和用于保护它们之间传递的数据的密钥。
为了提供必要的密钥,我们需要创建一个密钥库来保存密钥。当应用程序执行时,密钥库必须可供应用程序使用。首先,我们将演示如何创建密钥库,然后我们将向您展示必须提供哪些运行时参数。
您还需要bin
使用类似于以下命令的命令设置目录的路径。需要此命令来查找和执行keytool
应用程序:
set path= C:\Program Files\Java\jdk1.8.0_25\bin;%path%
接下来,输入keytool
命令。系统将提示您输入用于创建密钥的密码和其他信息。此处显示了此过程,其中使用了密码,123456
但在输入时未显示:
keytool -genkey -keyalg RSA -keystore C:\keystore.jks
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
[Unknown]:
您的组织单位名称是什么?
[Unknown]:
您的组织名称是什么?
[Unknown]:
您所在的城市或区域名称是什么?
[Unknown]:
您所在的省/市/自治区名称是什么?
[Unknown]:
该单位的双字母国家/地区代码是什么?
[Unknown]:
CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown是否正确?
[否]: y
创建密钥库后,您可以运行服务器和客户端应用程序。这些应用程序的启动方式取决于您的项目是如何创建的。您可以从 IDE 执行它,或者您可能需要从命令窗口启动它们。
接下来是可以从命令窗口使用的命令。该java
命令的两个参数是密钥库的位置和密码。它们需要从包目录的根目录执行:
java -Djavax.net.ssl.keyStore=keystore.jks -Djavax.net.ssl.keyStorePassword=123456 SSLServerSocket
java -Djavax.net.ssl.trustStore=keystore.jks -Djavax.net.ssl.trustStorePassword=123456 SSLClientSocket
如果要使用 IDE,请使用运行时命令参数的等效设置。下面的例子说明了客户端和服务器之间的一种可能的交换。服务器窗口的输出首先显示,然后是客户端的输出:
SSLServerSocket Started
Client socket created
Hello echo server
Safe and secure
SSLServerSocket Terminated
SSLClientSocket Started
Enter text: Hello echo server
Server response: Hello echo server
Enter text: Safe and secure
Server response: Safe and secure
Enter text: quit
SSLServerSocket Terminated