小编说:本文作者孙卫琴,知名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创建安全的数据通信相关推荐

  1. java nio 客户端_Java网络编程:Netty框架学习(二)---Java NIO,实现简单的服务端客户端消息传输...

    概述 上篇中已经讲到Java中的NIO类库,Java中也称New IO,类库的目标就是要让Java支持非阻塞IO,基于这个原因,更多的人喜欢称Java NIO为非阻塞IO(Non-Block IO), ...

  2. java并发排它锁_Java并发编程进阶——锁(解析)

    一.锁是什么 java开发中进行并发编程时针对操作同一块区域时,如果不加锁会出现并发问题,数据不是自己预计得到的值.我觉得有点像mysql事务中脏读.不可重复读.幻读的问题.加锁的目的是为了保证同一时 ...

  3. java 网络实验_java网络聊天室实验

    使用java写的一个网络聊天小程序,采用UDP协议.将左下角的ip改为目标地址即可发送信息.作为java网络编程入门的一个参考.最后一幅图为程序中所使用图片,来自仙剑奇侠传五的壁纸. 1.[文件] C ...

  4. java 函数式编程_Java函数式编程:Javaslang入门

    java 函数式编程 Java是一门古老的语言,并且该领域中有很多新手在他们自己的领域(JVM)上挑战Java. 但是Java 8到来并带来了一些有趣的功能. 这些有趣的功能使编写新的惊人框架(例如S ...

  5. java 编写异常_Java基础编程之异常处理

    Java异常类是对于程序中可能出现的错误或者异常的一种处理方式.在设计程序的过程中,对于可能出现的异常错误,比如说用户输入错误,设备错误,磁盘满了或者代码错误等等,通常采用异常处理的方式来进行处理可能 ...

  6. udp java 编程_JAVA 网络编程之UDP编程

    多线程,网络编程,反射,集合是java语言的重头戏,其中反射是java一切框架的基石. 客户端: SocketAddress sa =new  InetSocketAddress("10.1 ...

  7. Java基础通信_Java网络通信基础编程(必看篇)

    方式一:同步阻塞方式(BIO): 服务器端(Server): package com.ietree.basicskill.socket.mode1; import java.io.IOExceptio ...

  8. java nio 海子_java 网络编程入门-NIO

    这篇来讲解java网络编程之后高性能模型.NIO,有些书成为Non-blocking IO 非阻塞IO,这个是相对于BIO来说的.还有一种说法,New IO,顾名思义新的IO,这个是相对于旧版io的定 ...

  9. java socket 高级编程_Java高级编程-网络编程详细介绍 (一)

    java.net 包中的类和接口提供了可用于低层和高层网络编程的 API.低层 API 可以让你直接访问网络协议,但是为此你不得不使用低层的 TCP 套接字和 UDP 数据包.高层的 API (如 U ...

最新文章

  1. 数据可视化[python-pyecharts]制作中国各省份近三个月新型冠状病毒肺炎变化图
  2. 同一订单类型用多个号码段
  3. 电气论文实现:应用转移因子法求解大规模电力网络潮流
  4. python网络爬虫系列(三)——cookie的原理、保存与加载
  5. 网上书店管理系统java部分代码_网上书店管理系统 java语言
  6. UltraEdit的高亮【原创】
  7. 今日头条收购锤子?ofo 半月退 24 万户押金;斗鱼索赔主播 1.5 亿元 | 极客头条...
  8. C++11 关键字override和final
  9. java做安卓开发需要学什么,安卓开发要学什么 需要什么基础知识
  10. python 移动文件 覆盖_python 剪切移动文件的实现代码
  11. 【支付宝】支付宝ISV申请方法
  12. ubuntu安装系分区,挂载磁盘
  13. 社交红利的诞生与初期创业
  14. android自定义控件(星级评分)
  15. mysql spring lobhandler_Spring让LOB数据操作变得简单易行
  16. 唱给挚爱高妹(大头妹)的歌~~~
  17. pycharm快速注释快捷键
  18. 【Python爬虫】MongoDB爬虫实践:爬取虎扑论坛
  19. 51单片机实战教程(六 网线测试治具设计)
  20. 狼性团队五要素:沟通+信任+慎重+换位+快乐

热门文章

  1. 怎么查看WordPress主题HTML,几个WordPress 主题在线检测工具
  2. macOS Sierra 10.12 汉化软件无法安装
  3. 安卓学习笔记26:菜单
  4. 安卓学习笔记25:常用控件 - 下拉列表
  5. Python案例:通过方向键移动屏幕上的图像
  6. PHP案例:数组用法演示
  7. bzoj3231 [SDOI2008]递归数列 矩乘
  8. 2017.10.24 学校食堂Dining 失败总结
  9. 【英语学习】4000 Words 【V1】【U02】The Laboratory
  10. 【英语学习】【WOTD】pungle 释义/词源/示例