创建基于SSL的安全服务器和安全客户的范例
创建基于SSL的安全服务器和安全客户的范例
以下内容参考孙卫琴所写的《Java网络编程核心技术详解》一书的第15章。
源代码下载地址为:http://lesson.javathinker.net/javanet/javanetsourcecode.rar
以下EchoServer类创建了一个基于SSL的安全服务器,它处于服务器模式。
/* EchoServer.java */import java.net.*;import java.io.*;import javax.net.ssl.*;import java.security.*;public class EchoServer { private int port=8000; private SSLServerSocket serverSocket; public EchoServer() throws Exception { //输出跟踪日志 //System.setProperty("javax.net.debug", "all"); SSLContext context=createSSLContext(); SSLServerSocketFactory factory=context.getServerSocketFactory(); serverSocket =(SSLServerSocket)factory.createServerSocket(port); System.out.println("服务器启动"); System.out.println( serverSocket.getUseClientMode()? "客户模式":"服务器模式"); System.out.println(serverSocket.getNeedClientAuth()? "需要验证对方身份":"不需要验证对方身份"); String[] supported=serverSocket.getSupportedCipherSuites(); serverSocket.setEnabledCipherSuites(supported); } public SSLContext createSSLContext() throws Exception { //服务器用于证实自己身份的安全证书所在的密钥库 String keyStoreFile = "test.keystore"; String passphrase = "123456"; KeyStore ks = KeyStore.getInstance("JKS"); char[] password = passphrase.toCharArray(); ks.load(new FileInputStream(keyStoreFile), password); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, password); SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(kmf.getKeyManagers(), null, null); //当要求客户端提供安全证书时,服务器端可创建TrustManagerFactory, //并由它创建TrustManager,TrustManger根据与之关联的KeyStore中的信息, //来决定是否相信客户提供的安全证书。 //客户端用于证实自己身份的安全证书所在的密钥库 //String trustStoreFile = "test.keystore"; //KeyStore ts = KeyStore.getInstance("JKS"); //ts.load(new FileInputStream(trustStoreFile), password); //TrustManagerFactory tmf = // TrustManagerFactory.getInstance("SunX509"); //tmf.init(ts); //sslContext.init(kmf.getKeyManagers(), // tmf.getTrustManagers(), null); return sslContext; } public String echo(String msg) { return "echo:" + msg; } private PrintWriter getWriter(Socket socket)throws IOException{ OutputStream socketOut = socket.getOutputStream(); return new PrintWriter(socketOut,true); } private BufferedReader getReader(Socket socket)throws IOException{ InputStream socketIn = socket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn)); } public void service() { while (true) { Socket socket=null; try { socket = serverSocket.accept(); //等待客户连接 System.out.println("New connection accepted " +socket.getInetAddress() + ":" +socket.getPort()); BufferedReader br =getReader(socket); PrintWriter pw = getWriter(socket); String msg = null; while ((msg = br.readLine()) != null) { System.out.println(msg); pw.println(echo(msg)); if (msg.equals("bye")) //如果客户发送的消息为“bye”,就结束通信 break; } }catch (IOException e) { e.printStackTrace(); }finally { try{ if(socket!=null)socket.close(); //断开连接 }catch (IOException e) {e.printStackTrace();} } } } public static void main(String args[])throws Exception { new EchoServer().service(); }}
以上EchoServer类先创建了SSLContext对象,然后由它创建SSLServerSocketFactory对象,再由该工厂对象创建SSLServerSocket对象。对于以下程序代码:
System.out.println(serverSocket.getUseClientMode()? "客户模式":"服务器模式");System.out.println(serverSocket.getNeedClientAuth()? "需要验证对方身份":"不需要需要验证对方身份");
打印结果为:
服务器模式不需要验证对方身份
由此可见,默认情况下,SSLServerSocket处于服务器模式,必须向对方证实自身的身份,但不需要验证对方的身份,即不要求对方出示安全证书。
如果希望程序运行时输出底层JSSE实现的日志信息,可以把“javax.net.debug”系统属性设为“all”:System.setProperty("javax.net.debug", "all");
以下EchoClient类创建了一个基于SSL的安全客户,它处于客户模式。
/* EchoClient.java */import java.net.*;import java.io.*;import javax.net.ssl.*;import java.security.*;public class EchoClient { private String host="localhost"; private int port=8000; private SSLSocket socket; public EchoClient()throws IOException{ SSLContext context=createSSLContext(); SSLSocketFactory factory=context.getSocketFactory(); socket=(SSLSocket)factory.createSocket(host,port); String[] supported=socket.getSupportedCipherSuites(); socket.setEnabledCipherSuites(supported); System.out.println(socket.getUseClientMode()? "客户模式":"服务器模式"); } public SSLContext createSSLContext() throws Exception { String passphrase = "123456"; char[] password = passphrase.toCharArray(); //设置客户端所信任的安全证书所在的密钥库 String trustStoreFile = "test.keystore"; KeyStore ts = KeyStore.getInstance("JKS"); ts.load(new FileInputStream(trustStoreFile), password); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ts); SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null,tmf.getTrustManagers(), null); return sslContext; } public static void main(String args[])throws IOException{ new EchoClient().talk(); } private PrintWriter getWriter(Socket socket)throws IOException{ OutputStream socketOut = socket.getOutputStream(); return new PrintWriter(socketOut,true); } private BufferedReader getReader(Socket socket)throws IOException{ InputStream socketIn = socket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn)); } public void talk()throws IOException { try{ BufferedReader br=getReader(socket); PrintWriter pw=getWriter(socket); BufferedReader localReader= new BufferedReader(new InputStreamReader(System.in)); String msg=null; while((msg=localReader.readLine())!=null){ pw.println(msg); System.out.println(br.readLine()); if(msg.equals("bye")) break; } }catch(IOException e){ e.printStackTrace(); }finally{ try{socket.close();}catch(IOException e){e.printStackTrace();} } }}
以上EchoClient类先创建了一个SSLSocketFactory对象,然后由它创建了SSLSocket对象。对于以下程序代码:
System.out.println(socket.getUseClientMode()? "客户模式":"服务器模式");
打印结果为:
客户模式
由此可见,默认情况下,由SSLSocketFactory创建的SSLSocket对象处于客户模式,不必向对方证实自身的身份。
EchoClient类依靠TrustManager来决定是否信任EchoServer出示的安全证书。EchoClient类的SSLSocketFactory对象是由SSLContext对象来创建的。这个SSLContext对象通过TrustManager来管理所信任的安全证书。在本例中,TrustManager所信任的安全证书位于test.keystore密钥库文件中。
在本例中,服务器端向客户端出示的安全证书位于test.keystore密钥库文件中。在实际应用中,服务器端的密钥库文件中包含密钥对,从安全角度出发,客户端所信任的密钥库文件中应该仅仅包含公钥,所以服务器和客户端应该使用不同的密钥库文件。
假定该文件与EchoServer.class以及EchoClient.class文件位于同一目录下。在DOS命令行中转到范例所在的chapter15目录下,按照以下步骤运行EchoServer和EchoClient:
(1)设置classpath,运行命令“set classpath=C:\chapter15\classes”。
(2)运行“start java EchoServer”命令,启动EchoServer服务器。
(3)运行“ java EchoClient”命令,启动EchoClient客户。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。