小编说:本文作者孙卫琴,知名IT作家和Java专家。本文将通过一个范例向大家介绍JSSE是如何实现安全的网络通信的。
在网络上,信息在由源主机到目标主机的传输过程中会经过其他计算机。一般情况下,中间的计算机不会监听路过的信息。但在使用网上银行或者进行信用卡交易时,网络上的信息有可能被非法分子监听,从而导致个人隐私的泄露。
由于和体系结构存在一些安全漏洞,总有某些人能够截获并替换用户发出的原始信息。
随着电子商务的不断发展,人们对信息安全的要求越来越高,于是公司提出了SSL协议,目的为了能在开放网络上安全保密地传输信息。
Java安全套接字扩展(JSSE,Java )为基于SSL和TLS协议的Java网络应用程序提供了Java API以及参考实现。
JSSE支持数据加密、服务器端身份验证、数据完整性以及可选的客户端身份验证。使用JSSE,能保证采用各种应用层协议(比如HTTP、和FTP等)的客户程序与服务器程序安全地交换数据。
JSSE封装了底层复杂的安全通信细节,使得开发人员能方便地利用它来开发安全的网络应用程序。
下文参考了《Java网络编程核心技术详解》一书的第15章,将结合具体范例来向大家介绍JSSE的用法。
JSSE API 简介
JSSE封装了底层复杂的安全通信细节,使得开发人员能方便地都它来开发安全的网络应用程序。JSSE主要包括四个包:
JSSE具有以下重要特征:
下面展示了JSSE API的主要类框图。
JSSE中负责安全通信的最核心的类是 类与 类,它们分别是 与 类的子类。 对象由 创建,此外, 的 () 方法也会创建 。 对象由 ry 创建。 、 ry 以及 对象都由 对象创建。 类用于支持非阻塞的安全通信。
创建安全服务器
以下类创建了一个基于SSL的安全服务器,它处于服务器模式。
1/* EchoServer.java*/
2import java.net.*;
3import java.io.*;
4import javax.net.ssl.*;
5import java.security.*;
6
7public class EchoServer {
8 private int port=8000;
9 private SSLServerSocket serverSocket;
10
11 public EchoServer() throws Exception {
12 //输出跟踪日志
13 //System.setProperty("javax.net.debug", "all");
14 SSLContext context=createSSLContext();
15 SSLServerSocketFactory factory=context.getServerSocketFactory();
16 serverSocket =(SSLServerSocket)factory.createServerSocket(port);
17 System.out.println("服务器启动");
18 System.out.println(
19 serverSocket.getUseClientMode()? "客户模式":"服务器模式");
20 System.out.println(serverSocket.getNeedClientAuth()?
21 "需要验证对方身份":"不需要验证对方身份");
22
23 String[] supported=serverSocket.getSupportedCipherSuites();
24 serverSocket.setEnabledCipherSuites(supported);
25 }
26
27 public SSLContext createSSLContext() throws Exception {
28 //服务器用于证实自己身份的安全证书所在的密钥库
29 String keyStoreFile = "test.keystore";
30 String passphrase = "123456";
31 KeyStore ks = KeyStore.getInstance("JKS");
32 char[] password = passphrase.toCharArray();
33 ks.load(new FileInputStream(keyStoreFile), password);
34 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
35 kmf.init(ks, password);
36
37 SSLContext sslContext = SSLContext.getInstance("SSL");
38 sslContext.init(kmf.getKeyManagers(), null, null);
39
40 //当要求客户端提供安全证书时,服务器端可创建TrustManagerFactory,
41 //并由它创建TrustManager,TrustManger根据与之关联的KeyStore中的信息,
42 //来决定是否相信客户提供的安全证书。
43
44 //客户端用于证实自己身份的安全证书所在的密钥库
45 //String trustStoreFile = "test.keystore";
46 //KeyStore ts = KeyStore.getInstance("JKS");
47 //ts.load(new FileInputStream(trustStoreFile), password);
48 //TrustManagerFactory tmf =
49 // TrustManagerFactory.getInstance("SunX509");
50 //tmf.init(ts);
51 //sslContext.init(kmf.getKeyManagers(),
52 // tmf.getTrustManagers(), null);
53
54 return sslContext;
55 }
56
57 public String echo(String msg) {
58 return "echo:" + msg;
59 }
60
61 private PrintWriter getWriter(Socket socket)throws IOException{
62 OutputStream socketOut = socket.getOutputStream();
63 return new PrintWriter(socketOut,true);
64 }
65 private BufferedReader getReader(Socket socket)throws IOException{
66 InputStream socketIn = socket.getInputStream();
67 return new BufferedReader(new InputStreamReader(socketIn));
68 }
69
70 public void service() {
71 while (true) {
72 Socket socket=null;
73 try {
74 socket = serverSocket.accept(); //等待客户连接
75 System.out.println("New connection accepted "
76 +socket.getInetAddress()
77 + ":" +socket.getPort());
78 BufferedReader br =getReader(socket);
79 PrintWriter pw = getWriter(socket);
80
81 String msg = null;
82 while ((msg = br.readLine()) != null) {
83 System.out.println(msg);
84 pw.println(echo(msg));
85 if (msg.equals("bye")) //如果客户发送的消息为“bye”,就结束通信
86 break;
87 }
88 }catch (IOException e) {
89 e.printStackTrace();
90 }finally {
91 try{
92 if(socket!=null)socket.close(); //断开连接
93 }catch (IOException e) {e.printStackTrace();}
94 }
95 }
96 }
97
98 public static void main(String args[])throws Exception {
99 new EchoServer().service();
100 }
101}
以上类先创建了对象,然后由它创建ry对象,再由该工厂对象创建对象。对于以下程序代码:
1System.out.println(serverSocket.getUseClientMode()?
2 "客户模式":"服务器模式");
3System.out.println(serverSocket.getNeedClientAuth()?
4 "需要验证对方身份":"不需要需要验证对方身份");
打印结果为:
1服务器模式
2不需要验证对方身份
由此可见网络编程,默认情况下,处于服务器模式,必须向对方证实自身的身份,但不需要验证对方的身份,即不要求对方出示安全证书。
如果希望程序运行时输出底层JSSE实现的日志信息网络编程,可以把“.debug”系统属性设为“all”:
1System.setProperty("javax.net.debug", "all");
创建安全客户程序
以下类创建了一个基于SSL的安全客户,它处于客户模式
1/* EchoClient.java */
2import java.net.*;
3import java.io.*;
4import javax.net.ssl.*;
5import java.security.*;
6
7public class EchoClient {
8 private String host="localhost";
9 private int port=8000;
10 private SSLSocket socket;
11
12 public EchoClient()throws IOException{
13 SSLContext context=createSSLContext();
14 SSLSocketFactory factory=context.getSocketFactory();
15 socket=(SSLSocket)factory.createSocket(host,port);
16 String[] supported=socket.getSupportedCipherSuites();
17 socket.setEnabledCipherSuites(supported);
18 System.out.println(socket.getUseClientMode()?
19 "客户模式":"服务器模式");
20 }
21
22 public SSLContext createSSLContext() throws Exception {
23 String passphrase = "123456";
24 char[] password = passphrase.toCharArray();
25
26 //设置客户端所信任的安全证书所在的密钥库
27 String trustStoreFile = "test.keystore";
28 KeyStore ts = KeyStore.getInstance("JKS");
29 ts.load(new FileInputStream(trustStoreFile), password);
30 TrustManagerFactory tmf =
31 TrustManagerFactory.getInstance("SunX509");
32 tmf.init(ts);
33
34 SSLContext sslContext = SSLContext.getInstance("SSL");
35 sslContext.init(null,tmf.getTrustManagers(), null);
36 return sslContext;
37 }
38 public static void main(String args[])throws IOException{
39 new EchoClient().talk();
40 }
41 private PrintWriter getWriter(Socket socket)throws IOException{
42 OutputStream socketOut = socket.getOutputStream();
43 return new PrintWriter(socketOut,true);
44 }
45 private BufferedReader getReader(Socket socket)throws IOException{
46 InputStream socketIn = socket.getInputStream();
47 return new BufferedReader(new InputStreamReader(socketIn));
48 }
49 public void talk()throws IOException {
50 try{
51 BufferedReader br=getReader(socket);
52 PrintWriter pw=getWriter(socket);
53 BufferedReader localReader=
54 new BufferedReader(new InputStreamReader(System.in));
55 String msg=null;
56 while((msg=localReader.readLine())!=null){
57 pw.println(msg);
58 System.out.println(br.readLine());
59
60 if(msg.equals("bye"))
61 break;
62 }
63 }catch(IOException e){
64 e.printStackTrace();
65 }finally{
66 try{socket.close();}catch(IOException e){e.printStackTrace();}
67 }
68 }
69}
以上类先创建了一个对象,然后由它创建了对象。对于以下程序代码:
1System.out.println(socket.getUseClientMode()?"客户模式":"服务器模式");
打印结果为:
1客户模式
由此可见,默认情况下,由创建的对象处于客户模式,不必向对方证实自身的身份。
类依靠来决定是否信任出示的安全证书。类的对象是由对象来创建的。这个对象通过来管理所信任的安全证书。在本例中,所信任的安全证书位于test.密钥库文件中。
在本例中,服务器端向客户端出示的安全证书位于test.密钥库文件中。在实际应用中,服务器端的密钥库文件中包含密钥对,从安全角度出发,客户端所信任的密钥库文件中应该仅仅包含公钥,所以服务器和客户端应该使用不同的密钥库文件。
在 IT 行业,大多数 Java 程序员都看过孙卫琴老师的书。
孙老师的书,清晰严谨,把复杂的技术架构层层剖析,结合典型的实例细致讲解,读者只要静下心来好好品读,就能深入 Java 技术的殿堂!
如今,Java 在网络应用开发领域得到了非常广泛的运用,孙卫琴老师新书上市之际,博文视点学院联合孙老师共同打造技术视频课《Java网络编程核心技术详解》(含同名新书一本)!
通过课程+图书的学习,不仅可以帮助你掌握网络编程的实用技术,还可以进一步提高按照面向对象的思想来设计和开发Java软件的能力!
500+分钟的视频课,限时特惠仅需79元!(包含价值129元图书一本)
(扫码获取详情)
如果喜欢本文
限时特惠:本站持续每日更新海量各大内部创业课程,一年会员仅需要98元,全站资源免费下载
点击查看详情
站长微信:Jiucxh