Netty和SSL/TLS概说

        上周收到百度地图开发平台的一封邮件,说苹果AppStore要求:2017年1月1日起,所有上线苹果App Store的应用都必须启用 App Transport Security(ATS)安全功能。AppTransportSecurity(ATS)是苹果在iOS9中引入的一项隐私保护功能,屏蔽明文HTTP资源加载,连接必须经过更安全的HTTPS协议。(想想我们的一个客户端,用的百度地图好长时间没更新了,到时再不更新定位功能岂不是歇菜了?)

        最近看新闻,说网站从Http迁移到Https也是一种趋势。

        据此我们有理由相信:掌握点安全方面的编程还是有必要的!

        本文档的目标就是为了让像我这样的人也能够实现完整编码,而不是仅仅摸下Hello World!(最终代码下载)

        这里主要是介绍基于Netty框架,开发Socket、Http方面的程序,包括服务端和客户端,并支持SSL/TLS;以及如何使用OpenSSL、Keytool工具制作证书;同时,介绍下SSL/TLS协议、Wireshark抓包工具。此外,如果有可能,介绍一下Tomcat服务端和Netty客户端、Android客户端、iOS客户端之间的安全通信。

        本次试验环境是在Mac、Window系统上操作完成,用Mac也仅是方便了使用OpenSSL工具来制作CA证书——在Ubuntu上应该也方便。编程语言采用Java——Netty框架就是Java写的,这个没办法,所以你得会点Java编程,要不本文档只有制作证书部分可以参考。

        这里得提下Java的历史——那时哥还年轻。以前百姓总是说Java性能不行,总是不能来硬的——一涉及到服务性,就需要有指针可以到处插的C或C++来开天辟地。为啥这样?输入输出工作不到位咯,别人一个时辰接客38个,你却只接2个。只能说Java IO接口就是不好,开始通信模式还采用BIO模式,即同步阻塞——也就是一个一个的来,虽然显得彬彬有礼有秩序,但客户不爽不痛快。还好Java年轻力壮后劲足,不久来了个NIO非阻塞模式,后来又演变出AIO异步非阻塞模式,这下可好了,就算接客300头,腿不酸腰也不疼了——所以现在就算在天上人间这样的系统后台里看到她Java亮丽的身影和出色的功夫也不应该感到惊讶。

        人道是好事多磨,Java固然有了质的飞跃,但是她自带的NIO类库和API,又繁又杂很麻烦,就算再强壮潇洒的白码猿黑码猿也会搞出病来——反正我就不敢惹。

        于是,她应运而生。她强且大,灵活性能好而不失成熟稳定,是活跃的一线明星(接待过好多不同行业的商业客户),最重要的是她天生简单——无论北京人,还是海南人,见到她都像见到芙蓉姐一样感到自然和舒畅。因此,我们没有理由忽略她,她就是Netty,一款异步的事件驱动的网络应用框架和工具,用于快速开发可维护的高性能、高扩展性协议服务器和客户端。

        现在先去逛一下Netty的窑子:https://github.com/netty/netty/ ,邂逅一下代码例子,看能否擦出什么火花。

        沟通始于聊天。里面有个叫“securechat”的,各位客官,不妨也瞧瞧:

        Netty和SSL/TLS概说_第1张图片

                                                                        (图1)

       看这芳名,大概可猜出几分的意思,里面有服务,有前台,也有SSL安全措施,但只是用了她自家便宜的安全措施,而不是客户定制的,这个后面再说,不影响这里氛围。

       首先看 SecureChatServer 类,它开了两个舞池NioEventLoopGroup,一主一从————好像一个专门接客、一个专门干活,配置好通道Channel、安全措施,并绑好门窗端口,就开张营业坐等客人来了。

       再看SecureChatServerHandler类,生意的好坏就看它了,一有客人接入,深情道声“欢迎光临,可开发票”,接下来与客人的卿卿我我,好像都离不开它了。

       最后看SecureChatServerInitializer类,他比较纯真,就是吹填管道ChannelPipeline,需要什么安全措施,就往里面塞;跟客人定好什么对头暗号编码解码方法,也往里面塞;需要什么其它附加服务也往里面塞。

       正经点来说主要关注四个类:Channel、ChannelHandler、ChannelPipeline、ChannelHandlerContext。

       先看下它们关系图:

                          Netty和SSL/TLS概说_第2张图片

                                                                                      (图2)

                                  Netty和SSL/TLS概说_第3张图片

                                                                                          (图3)


        Channel是Netty最核心的接口,一个Channel就是一个联络Socket的通道,通过Channel,可以对Socket进行各种操作。

        用Netty编写网络程序的时候,很少直接操纵Channel,而是通过ChannelHandler来间接操纵Channel。

        ChannelHandler又分为 ChannelInboundHandler和ChannelOutboundHandler两大类。其中ChannelInboundHandler是用来接收并处理(解码)另一方发来的数据,ChannelOutboundHandler是用来处理数据(编码)并发给另一方。

        Netty中可以注册多个Handler,ChannelInboundHandler按照注册的先后顺序执行;ChannelOutboundHandler按照注册的先后顺序逆序执行。

        ChannelPipeline可以看成是一个ChandlerHandler的链表,当需要Channel进行某种处理的时候,Pipeline负责依次调用每一个Handler进行处理。每个Channel都有一个属于自己的Pipeline,调用Channel类的pipeline()方法可以获得该Channel的Pipeline,调用Pipeline的channel()方法可以获得该Pipeline所属的Channel。

        ChannelPipeline并不是直接管理ChannelHandler,而是通过ChannelHandlerContext来间接管理。在Pipeline内部,Context组成了一个双向链表,注册的各个handler就依次给连起来,但收到另一方消息,依次顺着链表,取出合适的handler来处理。

  Netty和SSL/TLS概说_第4张图片

                                                                                            (图4)


关于TCP

先看看网络分层模型:

Netty和SSL/TLS概说_第5张图片

                                                                                                     (图5)

Netty和SSL/TLS概说_第6张图片

                                                              (图6)

可以看出HTTP协议就是建立在TCP协议之上。

说到协议,顺便说下网络包分析工具:Wireshark。这里需要运行一个HTTP服务端和一个客户端,或打开一个网页,以便抓包。


Netty和SSL/TLS概说_第7张图片


                                                                            (图7)

  1.      Frame – 物理层
  2.      Ethernet – 数据链路层
  3.      Internet Protocol Version – 网络层
  4.     Transmission Control Protocol – 传输层
  5.      Hypertext Transfer Protocol -超文本协议
      我们主要关注第四层:传输层,而且主要关注TCP协议的三次握手过程,(运行一个Socket服务端和一个客户端,抓包看看)
Netty和SSL/TLS概说_第8张图片
                                                                                         (图8)


现在该看看SSL/TSL了

SSL是安全套接层(Secure Socket Layer)的缩写;

TLS表示传输层安全(Transport LayerSecurity)的缩写。

SSL最初由网景公司提出,最初目的是为了保护web安全,现在用来提高传输层的安全。

TLS是IETF基于SSLv3制定的标准,两者基本一致,只有少许的差别。

使用SSL/TLS的通信,就是为了防止信息被第三方窃听、篡改、冒充。

SSLv3/TLS处于传输层和应用层之间,分为握手层和记录层。

握手过程可以分成两种类型:

1)SSL/TLS 单向认证,客户端会认证服务器端身份,而服务器端不会去对客户端身份进行验证。(想想在浏览器访问一些Https网站)

2)SSL/TLS 双向认证,就是双方都会互相认证,也就是两者之间将会交换证书。(想想银行客户端)

          SSL/TLS所处位置


                                Netty和SSL/TLS概说_第9张图片
                                                                            (图9)

             握手过程:
Netty和SSL/TLS概说_第10张图片
                                                                             (图10)

 注:Finished亦是Encrypted Handshake Message

这个过程可以通过一个相亲过程来“解释”一下:(做了点添油加醋的步骤:Application Data、Encrypted Alert,但也属协议的一部分)

Netty和SSL/TLS概说_第11张图片
                                                                                                                   (图11)

说明:Server Key Exchange 跟所选加密算法有关,如果是RSA算法则不需要此步骤,若是DSA算法则需要。certificaterequest、certificate和certificate_verify在双向认证时才有,其中certificate_verify是客户端用自己的私钥签名前面握手消息的结果,给服务端认证客户端的证书certificate是否合法。


上面说了这么多,我想还是运行一下最终代码,抓包看看实际效果,也许更直观。

本人是在Mac上运行服务端,在虚拟机(window)上运行客户端和Wireshark。

(操作过程省去一万字)


证书制作

 (感觉有点长了,应该放到另外独立地方)

1 使用keytool自签名制作证书:

keytool是JDK自带工具。

1.1 单向认证

1) 生成Netty服务端私钥和证书仓库命令:

keytool -genkey-alias sserver -keysize 2048 -validity 365 -keyalg RSA -dname "CN=server,OU=HR, O=ESHORE, L=GZ, ST=GD, C=CN" -keypass servers -storepass servers-keystore server_s.jks

2) 生成Netty服务端自签名证书:

keytool -export-alias sserver -keystore server_s.jks -storepass servers -file server_s.cer

3) 生成客户端的密钥对和证书仓库,命令如下:

keytool -genkey-alias sclient -keysize 2048 -validity 365 -keyalg RSA -dname "CN=client,OU=HR2, O=ESHORE, L=GZ, ST=GD, C=CN" -keypass clients -storepass clients-keystore client_s.jks

4) 将Netty服务端的证书导入到客户端的证书仓库中,命令如下:

keytool -import-trustcacerts -alias sserver -file server_s.cer -storepass clients -keystore client_s.jks

 

1.2 双向认证(接上面的单向认证)

1) 生成客户端的自签名证书:

keytool -export -alias sclient -keystore client_s.jks -storepass clients -file client_s.cer

2) 将客户端的自签名证书导入到服务端的信任证书仓库中:

keytool -import -trustcacerts -alias sclient -file client_s.cer -storepass servers -keystore server_s.jks

 

2 基于第三方CA认证

        需要安装工具:OpenSSL 

先准备必要的目录和文件:

mkdir -p ./demoCA/{private,newcerts}

touchdemoCA/index.txt

echo 01 >demoCA/serial

 

2.1  服务端证书制作:

       这里根据两种算法:RSA和DSA 分别建立证书;如果不指明DSA,则属于RSA建立步骤。

步骤1:利用OpenSSL生成CA证书:

openssl req -new -x509 -keyout ca.key -out ca.crt -days 365

或分步:

openssl genrsa-des3 -out ./demoCA/private/cakey.pem 2048

openssl req -new -days 365 -key ./demoCA/private/cakey.pem -out careq.pem

openssl ca -selfsign -in careq.pem -out ./demoCA/cacert.pem

采用DRA算法建立:

/*生成1024位的密钥参数*/

openssl dsaparam-out DSAP.pem 1024

/*生成密钥并使用des3加密存储*/

openssl gendsa -out./demoCA/private/cakey_DSA.pem -des3 -passout pass:cakey DSAP.pem

openssl req -new -days 365 -key ./demoCA/private/cakey_DSA.pem -out careq_DSA.pem

/*执行下面命令前,需要把./demoCA/private/cakey_DSA.pem文件名改为cakey.pem */

openssl ca-selfsign -in careq_DSA.pem -out ./demoCA/cacert_DSA.pem

步骤2:生成Netty服务端私钥和证书仓库命令:

keytool -genkey -alias sserver -keysize 2048 -validity 365 -keyalg RSA -dname "CN=server,OU=HR, O=ESHORE, L=GZ, ST=GD, C=CN" -keypass serverkey -storepass servers -keystore server.jks

注意:上面命令中,由于-keypass和-storepass 密码设置不一样,导致服务端在接收到客户端连接请求时,报错:java.security.UnrecoverableKeyException: Cannot recover key

可以通过下面命令,把两个密码改为一样(都为servers),即可解决:

keytool -keypasswd -new servers -keystore server.jks -storepass servers -alias sserver -keypass serverkey

采用DRA算法建立:

keytool -genkey -alias sserver -keysize 1024 -validity 365 -keyalg DSA -dname "CN=server_DSA, OU=HR, O=ESHORE, L=GZ, ST=GD, C=CN" -keypass servers -storepass servers -keystore server_DSA.jks

步骤3:生成证书签名请求:

keytool -certreq-alias sserver -sigalg MD5withRSA -file server.csr -keypass serverkey -storepass servers -keystore server.jks

采用DRA算法建立:

keytool -certreq -alias sserver -sigalg SHA1withDSA -file server_DSA.csr -keypass servers -storepass servers -keystore server_DSA.jks

步骤4:用CA私钥进行签名:

openssl ca -inserver.csr -out server.crt

采用DRA算法建立:

openssl ca -inserver_DSA.csr -out server_DSA.crt -cert ./demoCA/cacert_DSA.pem -keyfile  ./demoCA/private/cakey_DSA.pem

步骤5:导入信任的CA根证书到keystore

keytool -import -v -trustcacerts -alias ca_root -file ./demoCA/cacert.pem -storepass servers -keystore server.jks

采用DRA算法建立:

keytool -import -v -trustcacerts -alias ca_root -file ./demoCA/cacert_DSA.pem -storepass servers -keystore server_DSA.jks

步骤6:将CA签名后的server端证书导入keystore

keytool -import -v -alias sserver -file server.crt -keypass servers -storepass servers -keystore server.jks

采用DRA算法建立:

keytool -import -v -alias sserver -file server_DSA.crt -keypass servers -storepass servers -keystore server_DSA.jks


2.2  客户端证书制作:

步骤1:生成客户端密钥对:

keytool -genkey -alias sclient -keysize 2048 -validity 365 -keyalg RSA -dname "CN=client,OU=HR2, O=ESHORE, L=GZ, ST=GD, C=CN" -keypass clients -storepass clients-keystore client.jks

采用DRA算法建立:

keytool -genkey -alias sclient -keysize 1024 -validity 365 -keyalg DSA -dname"CN=client_DSA, OU=HR2, O=ESHORE, L=GZ, ST=GD, C=CN" -keypass clients -storepass clients -keystore client_DSA.jks

步骤2:生成证书签名请求:

keytool -certreq -alias sclient -sigalg MD5withRSA -file client.csr -keypass clients -storepass clients -keystore client.jks

采用DRA算法建立:

keytool -certreq -alias sclient -sigalg SHA1withDSA -file client_DSA.csr -keypass clients -storepass clients -keystore client_DSA.jks

步骤3:用CA私钥进行签名:

openssl ca -in client.csr -out client.crt

采用DRA算法建立:

openssl ca -in client_DSA.csr -out client_DSA.crt -cert ./demoCA/cacert_DSA.pem -keyfile  ./demoCA/private/cakey_DSA.pem

步骤4:导入信任的CA根证书到keystore:

keytool -import -v -trustcacerts -alias ca_root -file ./demoCA/cacert.pem -storepass clients -keystore client.jks

采用DRA算法建立:

keytool -import -v -trustcacerts -alias ca_root -file ./demoCA/cacert_DSA.pem -storepass clients -keystore client_DSA.jks

步骤5:将CA签名后的client端证书导入keystore:

keytool -import -v -alias sclient -file client.crt -keypass clients -storepass clients -keystore client.jks

采用DRA算法建立:

keytool -import -v -alias sclient -file client_DSA.crt -keypass clients -storepass clients -keystore client_DSA.jks

 

证书制作完了,那在Tomcat中如何配置,使应用服务支持Https访问?其实也就是配置server.xml文件,下面是一个单向认证例子:

                   acceptCount="100"
           clientAuth="false"
           disableUploadTimeout="true"
           enableLookups="true"
           keystoreFile="xxx/server.jks"
           keystorePass="xxx"
           maxSpareThreads="75"
           maxThreads="200"
           minSpareThreads="5"
           port="8443"
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           scheme="https"
           secure="true" sslProtocol="TLS" />

keystoreFile就是制作的证书仓库文件(完整文件绝对路径),keystorePass是对应仓库密码。

如果想配置双向认证的,则在上面配置文件基础上再加上一项truststoreFile,并把clientAuth的值改为true,变为:

                   acceptCount="100"
           clientAuth="true"
           disableUploadTimeout="true"
           enableLookups="true"
           keystoreFile="xxx/server.jks"
           keystorePass="xxx"

           truststoreFile="xxx/server.jks"
           maxSpareThreads="75"
           maxThreads="200"
           minSpareThreads="5"
           port="8443"
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           scheme="https"
           secure="true" sslProtocol="TLS" />

 按上面建立仓库文件步骤,这里的truststoreFile是可以跟keystoreFile一样 的。

 这里也可以启动一个Tomcat应用来演示一下,试试用Netty开发的客户端连接Tomcat的Https服务,再用浏览器打开该地址,看结果如何;单向认证、双向认证配置对应的结果又如何。

 Android客户端的,参考:http://blog.csdn.net/yuxiaohui78/article/details/42117785

 iOS客户端的,参考: https://github.com/fengling2300/networkTest

(未完待续...)                              


参考资料:

 1、Netty系列之Netty安全性:

       http://www.infoq.com/cn/articles/netty-security

 2、Netty 各个类的讲解:

       http://blog.csdn.net/z69183787/article/details/52623501

 3、用Wireshark 图解 TCP 三次握手:

      http://blog.jobbole.com/108194/?utm_source=blog.jobbole.com&utm_medium=relatedPosts

 4、SSL协议详解:

      http://kb.cnblogs.com/page/162080/

 5、使用wireshark观察SSL/TLS握手过程--双向认证/单向认证:

      http://blog.csdn.net/fw0124/article/details/40983787

 6、HTTPS到底是个啥玩意儿:

      http://blog.csdn.net/zgwangbo/article/details/50889623

 7、图解SSL/TLS协议:

      http://blog.csdn.net/fw0124/article/details/40875629

 8、Handler的执行顺序:

      https://my.oschina.net/jamaly/blog/272385

 9、基于OpenSSL 的 CA 建立及证书签发:

      http://rhythm-zju.blog.163.com/blog/static/310042008015115718637/

 10、OpenSSL 非对称加密算法DSA命令详解:

      http://www.linuxidc.com/Linux/2016-04/130493.htm



你可能感兴趣的:(技术,Netty,SSL,HTTPS,OpenSSL,CA)