您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 7Java安全性编程实例
217第7章数据的安全传输和身份验证——SSL和HTTPS编程本章重点:本章在前面几章介绍的加密和认证技术的基础上,介绍如何使用SSL协议加密TCP/IP数据流,并介绍基于SSL的、用于加密浏览器和Web服务器之间通信的HTTPS协议。SSL和HTTPS不仅可以加密通信,而且可以用于服务器和客户身份的验证。用户浏览器访问一个站点,需要确定这个站点确实是某个机构的(说不定黑客已经攻击了你使用的域名服务器,将你导向了黑客伪装的一个站点)。服务器再某些时候也可能需要确定用户是谁,以便决定是否向其提供某类信息。本章对此作了介绍。本章主要内容:编制SSL客户和服务器程序编制HTTPS客户和服务器程序设置服务器所使用的证书设置客户程序信任的证书设置客户程序所使用的证书设置服务器信任的证书7.1最简单的SSL通信SSL编程使用客户机/服务器模式,二者之间的通信使用SSL协议进行加密。本节先通过最简单的程序介绍服务器和客户程序之间如何通过SSL进行加密通信。2187.1.1最简单的SSL服务器★实例说明本实例编写了一个最简单的SSL服务器程序,它接受客户程序建立连接,并以加密方式向客户程序发送一串字符Hi。SSL服务器程序运行时需要指定密钥库,以便向客户程序证明自己的身份。本实例演示了通过编程指定密钥库和通过java命令选项指定密钥库的两种运行方式。★编程思路:SSL编程和基于Socket的编程类似,首先创建ServerSocket对象,传入端口号,然后执行ServerSocket对象的accept()方法获取Socket类型的对象,并侦听端口以等待客户程序和服务器连接。最后通过Socket类型的对象获得输入和输出流,通过输入和输出流和客户程序进行通信。SSL编程和基于Socket的编程不同的地方在于其ServerSocket对象是通过一个特殊的对象:SSLServerSocketFactory类型的对象创建的,这样以后的输入和输出流将自动按照SSL协议指定的方法交换密钥并对数据进行加密。此外,需要指定包含证书的密钥库,以便客户程序确定SSL服务器是否可靠。具体步骤如下:(1)设置密钥库及口令System.setProperty(javax.net.ssl.keyStore,mykeystore);System.setProperty(javax.net.ssl.keyStorePassword,wshr.ut);分析:通过System类的静态方法setProperty()可以设置系统参数。方法的第一个参数是系统参数的名称,第二个参数是为系统参数设置的值。作为SSL服务器程序,主要需要设置两个系统参数:javax.net.ssl.keyStore指定密钥库的名称,219javax.net.ssl.keyStorePassword指定密钥库的密码。这里不妨使用5.1节得到的密钥库mykeystore,其密码为wshr.ut。密钥库中必须存放私钥和证书,此外为私钥设置的密码应该和密钥库的密码相同。程序将自动从密钥库中提取证书。(2)创建SSLServerSocketFactory类型的对象SSLServerSocketFactoryssf=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();分析:执行javax.net.ssl包中SSLServerSocketFactory类的静态方法getDefault(),经过强制转换获得SSLServerSocketFactory类型的对象,后面将用它获取ServerSocket对象。(3)创建ServerSocket类型的对象ServerSocketss=ssf.createServerSocket(5432);分析:执行上一步得到的SSLServerSocketFactory对象的createServerSocket()方法获得ServerSocket类型的对象,方法参数中指定一个整数作为端口号,其值一般在1~65535之间,其中1~1023一般用于知名的端口号或特定的UNIX服务,临时使用的端口号可取1024~65535之间的整数。一台计算机上往往会运行不同的服务程序提供不同的服务,这些程序应使用不同的端口号,这样,当服务器收到客户程序发来的请求时,通过端口号确定哪个服务器程序与之通信。(4)等待客户程序连接Sockets=ss.accept();分析:执行上一步得到的ServerSocket对象的accept()方法,程序将在此处挂起,等待客户程序建立连接。该方法返回的Socket类型的对象可用于和客户程序之间的通信。220(5)建立输出流PrintStreamout=newPrintStream(s.getOutputStream());out.println(Hi);分析:执行上一步得到的Socket对象的getOutputStream()方法可以得到输出流,通过该输出流发送的信息将加密传递给客户程序。这里不妨使用输出流创建PrintStream类型的对象,以便通过println()语句向客户程序打印字符串。如果服务器程序同时需要处理客户程序发来的字符串,可以再通过Socket对象的getInputStream()方法得到输入流,从输入流读取的信息即客户发来的信息。★代码与分析:完整代码如下:importjava.net.*;importjava.io.*;importjavax.net.ssl.*;publicclassMySSLServer{publicstaticvoidmain(Stringargs[])throwsException{System.setProperty(javax.net.ssl.keyStore,mykeystore);System.setProperty(javax.net.ssl.keyStorePassword,wshr.ut);SSLServerSocketFactoryssf=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();ServerSocketss=ssf.createServerSocket(5432);System.out.println(Waitingforconnection...);while(true){221Sockets=ss.accept();PrintStreamout=newPrintStream(s.getOutputStream());out.println(Hi);out.close();s.close();}}}为了让程序接受到一个连接请求并发送完“Hi”后能继续接受其他客户程序建立连接,程序中将Sockets=ss.accept()及其输入/输出处理放在了一个while循环当中。★运行程序由于SSL协议需要通过数字证书向客户表明服务器是否值得信任,因此当前目录下必须有密钥库,本实例不妨使用5.1节得到的密钥库mykeystore,将其拷贝到当前目录下,然后输入“javaMySSLServer”运行程序,当等待一段时间完成初始化后,屏幕显示:“Waitingforconnection...”,此时开始等待客户程序的连接。编程第1步设置系统参数也可以不在程序中指定,而是通过java命令选项来指定。例如如果省略了编程第1步,则可输入“java-Djavax.net.ssl.keyStore=mykeystore-Djavax.net.ssl.keyStorePassword=wshr.utMySSLServer”来运行程序,这样程序本身更具有灵活性。为了使客户程序能够顺利验证该服务器提供的证书,应该把mykeystore中所使用的证书或其签发者的证书提供给客户程序。这在下一小节“运行程序”部分将详细说明。2227.1.2最简单的SSL客户程序★实例说明本实例编写了一个最简单的SSL客户程序,它和运行7.1.1小节程序的计算机建立连接,接受其发来的字符串并自动对其进行解密。本实例同时演示了通过程序指定密钥库和通过java命令选项指定密钥库的两种运行方式。★编程思路:SSL客户端的编程也和基于Socket的客户端编程类似。首先得到Socket类型的对象,然后通过Socket类型的对象获得输入和输出流,通过输入和输出流和服务器程序进行通信。和服务器程序类似,SSL客户端编程和基于Socket的客户端编程不同的地方在于其Socket对象是通过一个特殊的对象:SSLSocketFactory类型的对象创建的。具体步骤如下:(1)设置客户程序信任的密钥库System.setProperty(javax.net.ssl.trustStore,clienttrust);分析:客户端欲和SSL服务器通信,则必须信任SSL服务器程序所使用的数字证书。因此客户程序应该将所信任的证书放在一个密钥库中(本实例“运行程序”部分给出了如何创建这样的密钥库)。这里不妨假定客户程序信任的证书放在文件名为clienttrust的密钥库中。通过System类的静态方法setProperty()可以设置系统参数javax.net.ssl.trustStore,可以在程序中指定该文件名。由于clienttrust中存放的只是可以公开的证书,因此程序中不需要给出密钥库的密码。(2)创建SSLSocketFactory类型的对象SSLSocketFactoryssf=(SSLSocketFactory)SSLSocketFactory.getDefault();223分析:执行javax.net.ssl包中SSLSocketFactory类的静态方法getDefault(),经过强制转换获得SSLSocketFactory类型的对象,后面将用它获取Socket对象。(3)创建Socket类型的对象,连接服务器程序Sockets=ssf.createSocket(127.0.0.1,5432);分析:执行上一步得到的SSLSocketFactory对象的createSocket()方法和服务器指定端口建立连接。方法的第一个参数是字符串形式的服务器IP地址或域名,如果只有一台计算机,客户和服务器程序都在同一台计算机上运行,则可以使用“127.0.0.1”作为服务器的IP地址,或“Localhost”作为服务器的域名。第二个参数即7.1.1小节的服务器程序在第3步指定的端口号。(4)建立输出流BufferedReaderin=newBufferedReader(newInputStreamReader(s.getInputStream()));Stringx=in.readLine()分析:执行上一步得到的Socket对象的getInputStream()方法可以得到输入流,通过该输入流读取服务器程序发送来的信息并自动解密。这里不妨使用输入流创建BufferedReader类型的对象,以便通过readLine()语句读取字符串。如果客户程序同时需要向服务器程序发送信息,可以再通过Socket对象的getOutputStream()方法得到输出流,通过输出流发送的信息可以被服务器程序的输入流读取到。★代码与分析:完整代码如下:importjava.net.*;importjava.io.*;224importjavax.net.ssl.*;publicclassMySSLClient{publicstaticvoidmain(Stringargs[])throwsException{System.setProperty(javax.net.ssl.trustStore,clienttrust);SSLSocketFactoryssf=(SSLSocketFactory)SSLSocketFactory.getDefault();Sockets=ssf.createSocket(127.0.0.1,5432);Bu
本文标题:7Java安全性编程实例
链接地址:https://www.777doc.com/doc-4550399 .html