java网络编程_Java网络编程进阶:通过JSSE创建安全的数据通信
小编说:本文作者孙卫琴,知名IT作家和Java专家。本文将通过一个范例向大家介绍JSSE是如何实现安全的网络通信的。
在网络上,信息在由源主机到目标主机的传输过程中会经过其他计算机。一般情况下,中间的计算机不会监听路过的信息。但在使用网上银行或者进行信用卡交易时,网络上的信息有可能被非法分子监听,从而导致个人隐私的泄露。
由于Internet和Intranet体系结构存在一些安全漏洞,总有某些人能够截获并替换用户发出的原始信息。
随着电子商务的不断发展,人们对信息安全的要求越来越高,于是Netscape公司提出了SSL协议,目的为了能在开放网络上安全保密地传输信息。
Java安全套接字扩展(JSSE,Java Secure Socket Extension)为基于SSL和TLS协议的Java网络应用程序提供了Java API以及参考实现。
JSSE支持数据加密、服务器端身份验证、数据完整性以及可选的客户端身份验证。使用JSSE,能保证采用各种应用层协议(比如HTTP、Telnet和FTP等)的客户程序与服务器程序安全地交换数据。
JSSE封装了底层复杂的安全通信细节,使得开发人员能方便地利用它来开发安全的网络应用程序。
下文参考了《Java网络编程核心技术详解》一书的第15章,将结合具体范例来向大家介绍JSSE的用法。
JSSE API 简介
JSSE封装了底层复杂的安全通信细节,使得开发人员能方便地用它来开发安全的网络应用程序。JSSE主要包括四个包:
- javax.net.ssl包:包括进行安全通信的类,比如SSLServerSocket和SSLSocket类。
- javax.net包:包括安全套接字的工厂类,比如SSLServerSocketFactory和SSLSocketFactory类。
- java.security.cert包:包括处理安全证书的类,如X509Certificate类。X.509是由国际电信联盟(ITU-T)制定的安全证书的标准。
- com.sun.net.ssl包:包括Oracle公司提供的JSSE的实现类。
JSSE具有以下重要特征:
- 纯粹用Java语言编写。
- 可以出口到大多数国家。
- 提供了支持SSL的JSSE API和JSSE实现。
- 提供了支持TLS的JSSE API和JSSE实现。
- 提供了用于创建安全连接的类,如SSLSocket、 SSLServerSocket 和 SSLEngine。
- 支持加密通信。
- 支持客户端和服务器端的身份验证。
- 支持SSL会话。
- JSSE的具体实现会支持一些常用的加密算法,比如RSA(加密长度2048位)、RC4(密钥长度128位)和DH(密钥长度1024位)。
下面展示了JSSE API的主要类框图。
JSSE中负责安全通信的最核心的类是 SSLServerSocket 类与SSLSocket 类,它们分别是 ServerSocket 与 Socket 类的子类。SSLSocket 对象由 SSLSocketFactory 创建,此外, SSLServerSocket 的 accept() 方法也会创建 SSLSocket。SSLServerSocket 对象由 SSLServerSocketFactory 创建。SSLSocketFactory 、 SSLServerSocketFactory 以及 SSLEngine 对象都由 SSLContext 对象创建。SSLEngine 类用于支持非阻塞的安全通信。
创建安全服务器
以下EchoServer类创建了一个基于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}
以上EchoServer类先创建了SSLContext对象,然后由它创建SSLServerSocketFactory对象,再由该工厂对象创建SSLServerSocket对象。对于以下程序代码:
1System.out.println(serverSocket.getUseClientMode()?2 "客户模式":"服务器模式");3System.out.println(serverSocket.getNeedClientAuth()?4 "需要验证对方身份":"不需要需要验证对方身份");
打印结果为:
1服务器模式2不需要验证对方身份
由此可见,默认情况下,SSLServerSocket处于服务器模式,必须向对方证实自身的身份,但不需要验证对方的身份,即不要求对方出示安全证书。
如果希望程序运行时输出底层JSSE实现的日志信息,可以把“javax.net.debug”系统属性设为“all”:
1System.setProperty("javax.net.debug", "all");
创建安全客户程序
以下EchoClient类创建了一个基于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;1112 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 }2122 public SSLContext createSSLContext() throws Exception {23 String passphrase = "123456";24 char[] password = passphrase.toCharArray();2526 //设置客户端所信任的安全证书所在的密钥库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);3334 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());5960 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}
以上EchoClient类先创建了一个SSLSocketFactory对象,然后由它创建了SSLSocket对象。对于以下程序代码:
1System.out.println(socket.getUseClientMode()?"客户模式":"服务器模式");
打印结果为:
1客户模式
由此可见,默认情况下,由SSLSocketFactory创建的SSLSocket对象处于客户模式,不必向对方证实自身的身份。
EchoClient类依靠TrustManager来决定是否信任EchoServer出示的安全证书。EchoClient类的SSLSocketFactory对象是由SSLContext对象来创建的。这个SSLContext对象通过TrustManager来管理所信任的安全证书。在本例中,TrustManager所信任的安全证书位于test.keystore密钥库文件中。
在本例中,服务器端向客户端出示的安全证书位于test.keystore密钥库文件中。在实际应用中,服务器端的密钥库文件中包含密钥对,从安全角度出发,客户端所信任的密钥库文件中应该仅仅包含公钥,所以服务器和客户端应该使用不同的密钥库文件。
在 IT 行业,大多数 Java 程序员都看过孙卫琴老师的书。
孙老师的书,清晰严谨,把复杂的技术架构层层剖析,结合典型的实例细致讲解,读者只要静下心来好好品读,就能深入 Java 技术的殿堂!
如今,Java 在网络应用开发领域得到了非常广泛的运用,孙卫琴老师新书上市之际,博文视点学院联合孙老师共同打造技术视频课《Java网络编程核心技术详解》(含同名新书一本)!
通过课程+图书的学习,不仅可以帮助你掌握网络编程的实用技术,还可以进一步提高按照面向对象的思想来设计和开发Java软件的能力!
热文推荐
- 声纹技术:让智能语音助手真正“认得”自己
- 为什么人人都需要懂一点高阶(中台)产品思维
- 苏杰:如果可以重来,你还会做工作狂么?
- 超详细丨完整的推荐系统架构设计
java网络编程_Java网络编程进阶:通过JSSE创建安全的数据通信相关推荐
- java nio 客户端_Java网络编程:Netty框架学习(二)---Java NIO,实现简单的服务端客户端消息传输...
概述 上篇中已经讲到Java中的NIO类库,Java中也称New IO,类库的目标就是要让Java支持非阻塞IO,基于这个原因,更多的人喜欢称Java NIO为非阻塞IO(Non-Block IO), ...
- java并发排它锁_Java并发编程进阶——锁(解析)
一.锁是什么 java开发中进行并发编程时针对操作同一块区域时,如果不加锁会出现并发问题,数据不是自己预计得到的值.我觉得有点像mysql事务中脏读.不可重复读.幻读的问题.加锁的目的是为了保证同一时 ...
- java 网络实验_java网络聊天室实验
使用java写的一个网络聊天小程序,采用UDP协议.将左下角的ip改为目标地址即可发送信息.作为java网络编程入门的一个参考.最后一幅图为程序中所使用图片,来自仙剑奇侠传五的壁纸. 1.[文件] C ...
- java 函数式编程_Java函数式编程:Javaslang入门
java 函数式编程 Java是一门古老的语言,并且该领域中有很多新手在他们自己的领域(JVM)上挑战Java. 但是Java 8到来并带来了一些有趣的功能. 这些有趣的功能使编写新的惊人框架(例如S ...
- java 编写异常_Java基础编程之异常处理
Java异常类是对于程序中可能出现的错误或者异常的一种处理方式.在设计程序的过程中,对于可能出现的异常错误,比如说用户输入错误,设备错误,磁盘满了或者代码错误等等,通常采用异常处理的方式来进行处理可能 ...
- udp java 编程_JAVA 网络编程之UDP编程
多线程,网络编程,反射,集合是java语言的重头戏,其中反射是java一切框架的基石. 客户端: SocketAddress sa =new InetSocketAddress("10.1 ...
- Java基础通信_Java网络通信基础编程(必看篇)
方式一:同步阻塞方式(BIO): 服务器端(Server): package com.ietree.basicskill.socket.mode1; import java.io.IOExceptio ...
- java nio 海子_java 网络编程入门-NIO
这篇来讲解java网络编程之后高性能模型.NIO,有些书成为Non-blocking IO 非阻塞IO,这个是相对于BIO来说的.还有一种说法,New IO,顾名思义新的IO,这个是相对于旧版io的定 ...
- java socket 高级编程_Java高级编程-网络编程详细介绍 (一)
java.net 包中的类和接口提供了可用于低层和高层网络编程的 API.低层 API 可以让你直接访问网络协议,但是为此你不得不使用低层的 TCP 套接字和 UDP 数据包.高层的 API (如 U ...
最新文章
- 数据可视化[python-pyecharts]制作中国各省份近三个月新型冠状病毒肺炎变化图
- 同一订单类型用多个号码段
- 电气论文实现:应用转移因子法求解大规模电力网络潮流
- python网络爬虫系列(三)——cookie的原理、保存与加载
- 网上书店管理系统java部分代码_网上书店管理系统 java语言
- UltraEdit的高亮【原创】
- 今日头条收购锤子?ofo 半月退 24 万户押金;斗鱼索赔主播 1.5 亿元 | 极客头条...
- C++11 关键字override和final
- java做安卓开发需要学什么,安卓开发要学什么 需要什么基础知识
- python 移动文件 覆盖_python 剪切移动文件的实现代码
- 【支付宝】支付宝ISV申请方法
- ubuntu安装系分区,挂载磁盘
- 社交红利的诞生与初期创业
- android自定义控件(星级评分)
- mysql spring lobhandler_Spring让LOB数据操作变得简单易行
- 唱给挚爱高妹(大头妹)的歌~~~
- pycharm快速注释快捷键
- 【Python爬虫】MongoDB爬虫实践:爬取虎扑论坛
- 51单片机实战教程(六 网线测试治具设计)
- 狼性团队五要素:沟通+信任+慎重+换位+快乐
热门文章
- 怎么查看WordPress主题HTML,几个WordPress 主题在线检测工具
- macOS Sierra 10.12 汉化软件无法安装
- 安卓学习笔记26:菜单
- 安卓学习笔记25:常用控件 - 下拉列表
- Python案例:通过方向键移动屏幕上的图像
- PHP案例:数组用法演示
- bzoj3231 [SDOI2008]递归数列 矩乘
- 2017.10.24 学校食堂Dining 失败总结
- 【英语学习】4000 Words 【V1】【U02】The Laboratory
- 【英语学习】【WOTD】pungle 释义/词源/示例