`
dannyhz
  • 浏览: 387194 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

使用ssl/tls 看如何查看java 网络安全传输

 
阅读更多
http://blog.csdn.net/dave_luo/article/details/5746545


 在前文中,我们通过实例了解了使用java加密的一些技术,它们各自具有一些优缺点,由于它们的一些局限性,在网络传输中,需要综合使用这些技术来保证高强度的传输安全性。本单元将讨论SSL/TLS,并用jdk中的JSSE(Java Secure Socket Extension)包编写一些简单实例,最后会用wireshark工具来分析使用SSL/TLS进行通信的工作流程。

     SSL

      SSL由Netscape提出,在经历了3个版本之后,由IETF将其标准化,成为TLS,在rfc2246中,详细描述了该协议的目标、作用和细节。SSL/TLS在整个tcp/ip协议栈中的位置如图1所示:

                         图1 SSL/TLS在tcp/ip协议栈中的位置

               

 

      正如图1所描绘的,SSL/TLS由两层协议组成,Record Protocol将需要传输的消息分解成易于管理的小块,可选择性的压缩这些小块数据,附加上它们的MAC值,然后加密这些数据,最后传递给传输层协议去处理(如图2所示);接收数据的时候,则进行相反的操作:解密数据,用MAC值进行验证,解压,然后重新组装成完整消息传递给上层协议处理。

                                      图2 SSL封包过程

                

 

      Record Protocol也是分层协议,它会对需要传输的消息附加上消息头用于描述协议相关信息,我们也可以从图2中看到这些消息头字段,Type表示封装的record类型,在TLSv1中,有4个类型:change_cipher_spec(通告对端进入加密模式)、alert(发出报警消息)、handshake(建立安全连接)、application_data(应用层数据);Version标识了所使用的SSL版本,对于TLSv1来说,主版本号为3,小版本号为1,3.1这个版本号有一定的历史原因,因为TLSv1是在SSLv3基础上制定的,差距甚微,所以只能算3.0版本的一个修订版;Length标识了数据部分的长度,每次压缩、加密、计算数字摘要之后都要重新填入处理后的数据长度;Data表示需要传递的消息,当Type不同时,这些数据可能是应用层协议产生的消息,也可能是Handshake Protocol、Change Cipher Spec Protocol和Alert Protocol产生的消息;MAC标识了record的数字签名,它被用来检测record的完整性。

      Handshake Protocol被用来在实际的传输之前,对通讯的双方进行身份验证,协商加密算法,用Change Cipher Spec Protocol通知对端进入对称加密模式,而Alter Protocol则用来向通讯的另一方发出警告消息,比如close_notify、bad_record_mac等。

接下来我们先看一个实际的例子,对SSL协议建立一个直观的印象,然后再讨论它的工作流程。

      JSSE示例

      我们的示例使用这样的场景:SSLServer在8266端口侦听SSLClient的连接,SSLClient向SSLServer发起连接请求,并要求验证SSLServer的身份合法性,建立连接之后,向SSLServer发一条消息”Hello World”,SSLServer接收到消息后打印屏幕上。由于SSL用公钥加密的技术来建立连接,用数字证书来验证对端身份合法性,因此在编写实例之前,我们先用keytool为Server和Client创建两对密钥,并将Server的数字证书导入到Client的受信密钥库中。

      # 为Server创建证书和密钥库  

keytool -genkey -alias server -keysize 512 -keyalg RSA -dname "CN=znest.cn,OU=Security,O=Znest,L=C,ST=H,C=CN" -keypass 123456 -storepass 123456 -keystore server.ks  

# 为Client创建证书和密钥库  

keytool -genkey -alias client -keysize 512 -keyalg RSA -dname "C=CN" -keypass 123456 -storepass 123456 -keystore client.ks  

# 导出Server的证书  

keytool -export -trustcacerts -alias server -keystore server.ks -storepass 123456 -file server_cert  

# 将Server的证书导入到Client的密钥库  

keytool -import -trustcacerts -alias server -keystore client.ks -storepass 123456 -file server_cert 
 

 



      接下来编写SSLServer.java:


import java.io.BufferedReader;  
import java.io.FileInputStream;  
import java.io.IOException;  
import java.io.InputStreamReader; 
import java.io.UnsupportedEncodingException;  
import java.security.KeyStore;  
import java.security.SecureRandom;  
import javax.net.ssl.KeyManager;  
import javax.net.ssl.KeyManagerFactory;  
import javax.net.ssl.SSLContext;  
import javax.net.ssl.SSLServerSocket;  
import javax.net.ssl.SSLServerSocketFactory;  
import javax.net.ssl.SSLSocket;  
import javax.net.ssl.TrustManager;  
import javax.net.ssl.TrustManagerFactory;  

public class SSLServer {  
    private static final int port = 8266;  
    private static final String keyStore = "server.ks";  
    private static final String trustStore = "server.ks";  
    private static final String keyStoreType = "jks";  
    private static final String trustStoreType = "jks";  
    private static final String keyStorePassword = "123456";  
    private static final String trustStorePassword = "123456";  
    private static final String secureRandomAlgorithm = "SHA1PRNG";  
    private static final String protocol = "TLSv1";  
    
    private static KeyManager[] createKeyManagersAsArray() throws Exception {  
        KeyStore ks = KeyStore.getInstance(keyStoreType);  
        ks.load(new FileInputStream(keyStore), keyStorePassword.toCharArray());  
        KeyManagerFactory tmf = KeyManagerFactory.getInstance(KeyManagerFactory  
            .getDefaultAlgorithm());  
        tmf.init(ks, keyStorePassword.toCharArray());  
        return tmf.getKeyManagers();  
    }  
  
    private static TrustManager[] createTrustManagersAsArray() throws Exception {  
        KeyStore ks = KeyStore.getInstance(trustStoreType);  
        ks.load(new FileInputStream(trustStore), trustStorePassword  
            .toCharArray()); 
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());  
        tmf.init(ks);  
        return tmf.getTrustManagers();  
    }  
   
    private static SSLServerSocket getServerSocket(int thePort) {  
        SSLServerSocket socket = null;  
        try {  
            SSLContext sslContext = SSLContext.getInstance(protocol);  
            sslContext.init(createKeyManagersAsArray(),  
                createTrustManagersAsArray(), SecureRandom  
                    .getInstance(secureRandomAlgorithm));     
            SSLServerSocketFactory factory = sslContext  
                .getServerSocketFactory();  
            socket = (SSLServerSocket) factory.createServerSocket(thePort);  
            //socket.setNeedClientAuth(true);  
        } catch (Exception e) {  
            System.out.println(e);  
        }  
        return (socket);  
    } 

    public static void main(String args[]) throws IOException {  
        SSLServerSocket server = getServerSocket(port);  
        System.out.println("在" + port + "端口等待连接...");  
        while (true) {  
            final SSLSocket socket = (SSLSocket) server.accept();  
             new Thread(new Runnable() {  
                public void run() {  
                    BufferedReader in;  
                    try {  
                        in = new BufferedReader(new InputStreamReader(socket  
                            .getInputStream(), "gb2312"));  
                        String msg = in.readLine();  
                        System.out.println(msg);  
                        socket.close();  
                    } catch (UnsupportedEncodingException e) {  
                        e.printStackTrace();  
                    } catch (IOException e) {  
                        e.printStackTrace();  
                    }  
                }  
            }).start();  
        }  
    }  
} 
 

 

以及SSLClient.java:

import java.io.PrintWriter;  
import java.net.Socket; 
import javax.net.ssl.SSLSocketFactory;

public class SSLClient {  
    private static String addr = "192.168.80.86";   

    public static void main(String args[]) {
        try {  
            System.setProperty("javax.net.ssl.keyStore", "client.ks"); 
            System.setProperty("javax.net.ssl.keyStorePassword", "123456");
            System.setProperty("javax.net.ssl.keyStoreType", "jks");  
            System.setProperty("javax.net.ssl.trustStore", "client.ks");  
            System.setProperty("javax.net.ssl.trustStorePassword", "123456");  
            System.setProperty("javax.net.ssl.trustStoreType", "jks");  
            SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory  
                .getDefault();  
            Socket socket = factory.createSocket(addr, 8266);  
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);  
            out.println("hello world!");  
            out.close();  
            socket.close();  
        } catch (Exception e) {  
            System.out.println(e);  
        }  
    }  
} 
 

 

      SSLContext扮演着创建SSL套接字工厂和一些其他SSL部件的角色,上面这两段代码展示了两种初始化SSLContext的方法,初始化SSLContext之后,生成SSLSocketFactory,之后的编程就和普通的socket编程没有什么区别了。为了保证运行,需要将编译后生成的SSLServer.class和server.ks放在同一目录下,将编译后生成的SSLClient.class和client.ks放在同一目录下,以便SSLContext能够从密钥库读取密钥和证书。

      SSL协议分析

      我们在192.168.80.86机器上打开wireshark监听流经该网卡的所有数据包,同时将SSLServer.class和server.ks放在这台机器上,然后执行下面的命令运行服务端程序准备接受客户端的连接请求。

java -cp . SSLServer 

 

将SSLClient.class和client.ks放在192.168.80.160机器上,执行下面的命令连接服务端。

 

java -cp . SSLClient 

      当客户端发出的”Hello World!”在服务端的屏幕上显示之后,wireshark将记录SSL的整个连接和停止过程。为了让wireshark能够解码ssl消息头,还需要在菜单“Analyze->Decode as…”设置解码类型,如图3所示。设置完毕后,wireshark将解析出tlsv1的数据包,如图4所示。

                                 图3 设置wireshark解码类型

                  

 

                            图4 wireshark主界面

 

          、

1-3行 三次握手建立tcp连接。

4行 客户端向服务端发送Client Hello,这个信息中包括它所支持的加密算法和用于生成密钥的随机数。

5行 服务端向客户端发送三条消息:(1)Server Hello包含了服务端所选择的算法(2)Certificate包含了用于验证服务器身份的证书或者证书链(3)Server Hello Done表示服务端完成了最初的加密算法协商步骤。

6行 由于服务端不需要验证客户端,因此客户端验证完服务端的身份之后,抽取服务器证书中的公钥,用这把公钥将它产生的用于之后数据交换时加密的密钥用非对称加密技术加密,并发送给服务端。

8行 客户端向服务端发送了两条消息:(1)Change cipher spec通知服务端进入对称加密模式(2)Finished通知服务端已经准备好加密传输数据了。

9行 服务端向客户端发送Change cipher spec通知客户端进入对称加密模式

11行 服务端向客户端发送Finished通知客户端已经准备好加密传输数据。

12行 客户端和服务端用对称加密算法和客户端生成的密钥加密传输应用层的数据。

13-15行 通告关闭连接

16行 客户端发送RST包关闭连接

这个过程正好和JSSE参考文档中的图一致:



     小结

      本文讨论了SSL/TLS,并用JSSE编写了一个示例。SSL/TLS使用数字证书来验证通信双方的合法性,使用非对称加密技术来协商数据传输的密钥,使用数字摘要来验证握手过程中消息的完整性,使用对称加密技术来传输数据,因此要完全掌握这个协议,需要对加密技术有深入了解。当然,对于大多数程序员来说,只需要简单的了解一下这些东西,熟悉JSSE,就能编写出具备一定安全强度的通信软件。 



分享到:
评论

相关推荐

    基于SSL/TLS协议的FTP客户端和服务器端

    SSL/TLS协议是网络安全领域的基石,主要用于保障网络数据传输的安全性。它通过加密技术,使得数据在网络中传输时以密文形式存在,防止中间人攻击。同时,它还提供了身份验证机制,确保通信双方的身份可信。 **Java...

    JAVA实现的SSL/TLS双向认证源代码

    总的来说,实现Java的SSL/TLS双向认证需要对网络安全和Java的SSL/TLS API有深入的理解。通过`keytool`和`openssl`管理证书,以及在`TeslaSSLServer`和`TeslaSSLClient`中配置SSLContext,我们可以创建安全的双向认证...

    Netty和SSL/TLS应用例子

    SSL(Secure Sockets Layer)和TLS(Transport Layer Security)是网络安全传输层的重要协议,它们为网络通信提供了加密处理,确保了数据在网络中的安全传输。 本示例代码着重展示了如何在Netty中集成SSL/TLS,以...

    基于 MINA 的 TLS/SSL NIO Socket 实现(二)

    本文将主要关注在Java中使用MINA来实现安全套接层(SSL)和传输层安全(TLS)协议,这两个协议是网络安全通信的基础,确保数据在网络中的加密传输。 首先,理解TLS/SSL的核心概念至关重要。它们都是为网络通信提供...

    Java Socket 实现SMTP邮件发送,支持SSL/TSL

    Java Socket编程是Java网络编程的基础,它提供了网络通信的能力,使得程序可以与其他计算机上的服务进行交互。在本案例中,我们将关注如何使用Java Socket来实现SMTP(Simple Mail Transfer Protocol)邮件发送,并...

    Java实现SSL TLS

    SSL(Secure Sockets Layer)和其后续版本 TLS(Transport Layer Security)是网络安全协议,用于在互联网上提供加密通信和身份验证。这个文档旨在为使用 Java 实现 SSL/TLS 提供一个简明易懂的指南。对于没有SSL...

    发邮件,支持SSL\TLS,支持Gmail、Hotmail、yahoo

    为了确保邮件的安全传输,SSL(Secure Sockets Layer)和TLS(Transport Layer Security)协议被广泛采用。本项目针对“发邮件,支持SSL\TLS,支持Gmail、Hotmail、yahoo”的需求,提供了一种解决方案,使得开发者...

    javaSSL.zip

    Java SSL(Secure Socket Layer)和TLS(Transport Layer Security)是网络安全通信的重要组成部分,主要用于加密传输数据,确保网络上的敏感信息不被窃取或篡改。Java平台提供了对SSL/TLS协议的支持,使得开发者...

    SSL+socket 详解-概念

    总而言之,SSL/TLS协议是保证互联网安全传输的核心技术,而JSSE作为一个重要的工具库,使得Java应用程序能够在不直接处理底层加密算法和协议细节的情况下,安全地实现SSL/TLS协议。在实际应用中,正确和安全地使用...

    android+java ssldemo

    在Android平台上,SSL(Secure Sockets Layer)与TLS(Transport Layer Security)协议是用于实现安全网络通信的关键技术。本文将深入探讨"android+java ssldemo"中的核心知识点,包括SSL/TLS协议的工作原理、双向...

    SMTP发送邮件程序(支持SSL和TLS)

    SMTP(Simple Mail Transfer Protocol)是互联网上用于发送电子邮件的标准协议,而SSL(Secure Sockets Layer)和TLS(Transport Layer Security)则是提供网络通信安全的重要技术。在这个“SMTP发送邮件程序”中,...

    TLS/SSL Socket 实现

    这两个协议是网络安全传输的重要组成部分,主要目的是在互联网上提供数据的加密、服务器身份验证以及消息完整性,以保护用户信息的安全。 在SSL/TLS协议栈中,一个基本的概念是“握手过程”。这个过程包括客户端和...

    基于Java的实例源码-SSL及HTTPS协议实例源码.zip

    在IT领域,尤其是在网络安全和网络通信方面,SSL(Secure Socket Layer)和其升级版TLS(Transport Layer Security)协议是至关重要的。这些协议确保了通过互联网传输的数据的安全性,特别是对于涉及敏感信息如银行...

    SSL的资料(含openssl的java简单例子)

    SSL(Secure Sockets Layer,安全套接层)是一种网络安全协议,用于在互联网上提供安全通信。它通过加密传输数据,确保信息在传输过程中不被窃取或篡改。SSL广泛应用于网上银行、电子商务、电子邮件和其他敏感信息...

    java网络文件传输(c/s)

    - 文件传输的安全性是重要考量,可以通过加密传输或使用安全套接层(SSL/TLS)来保护数据的安全。 - 为了提高性能,可以采用缓冲技术,批量读写数据,减少I/O操作的开销。 - 使用异步编程模型,如Java的...

    ftps和https双向认证demo

    `ftps`(FTP over SSL/TLS)和`https`(HTTP Secure)是两种广泛使用的安全协议,用于确保文件传输和网页浏览的安全性。本篇文章将深入探讨`ftps`和`https`的双向认证机制,以及如何使用`pfx`和`jks`证书实现这一...

    javaSSL代码

    10. **安全性最佳实践**: 定期更新密钥和证书,避免使用已知不安全的密码套件,禁用过时的SSL/TLS版本,这些都是提高网络安全性的基本措施。 博客中可能详细讨论了这些概念,以及如何在实际项目中应用它们。通过...

    JAVA的SSL项目,(让自己写的JAVA更加安全!)

    SSL/TLS(Transport Layer Security)协议是网络安全的基石,主要用于保护网络上的数据传输。它通过公钥和私钥加密技术来确保数据不被窃取,同时通过证书验证服务器的身份,防止中间人攻击。 2. **Java中的JSSE**...

    SSL.rar_JAVA SSL _ssl_ssl java

    Java中的SSL支持是通过JSSE(Java Secure Socket Extension)实现的,这是一个为Java平台提供安全套接层(SSL)和传输层安全(TLS)协议的API。 标题"SSL.rar_JAVA SSL _ssl_ssl java"表明这个压缩包包含的是关于...

Global site tag (gtag.js) - Google Analytics