介绍上一篇我们讲了如何使用netty创建聊天室,但是这么简单的聊天室太容易被窃听了。如果要说private在里面很不安全,怎么办?学过密码学的朋友可能想到了解决办法,聊天的时候加密消息,处理的时候解密消息。当然以上在netty中的工作并不需要我们手动去实现。Netty已经提供了支持SSL的通道供我们选择。让我们来看看。PKI标准在说netty的具体支持之前,我们需要了解公钥和私钥的加密标准体系PKI。PKI的全称是PublicKeyInfrastructure,即公钥系统。用于规范公钥私募的加解密规则,方便不同系统的对接。事实上,PKI标准有两代协议。第一代PKI标准主要由美国RSA公司的公钥加密标准PKCS、国际电信联盟的ITU-TX.509、IETF的X.509、WAP和WPKI等标准组成。但是,由于第一代PKI标准是基于抽象语法符号ASN.1编码的,比较复杂,实现起来也比较困难,所以产生了第二代PKI标准。第二代PKI标准是微软、VeriSign和webMethods于2001年发布的基于XML的密钥管理规范,也称为XKMS。事实上,CA中心最常用的规范是X.509系列和PKCS系列。X.509系列主要包括X.209、X.500和X.509,其中X.509是国际电信联盟(ITU-T)制定的数字证书标准。X.500在X.500的基础上进行了功能增强,1988年发布了X.509。X.509证书由用户公钥和用户标识符组成。此外,还包括版本号、证书序列号、CA标识、签名算法标识、颁发者名称、证书有效期等信息。PKCS是美国RSA公司的公钥加密标准,包括证书申请、证书更新、证书吊销表发布、扩展证书内容、数字签名、数字信封格式等一系列相关协议。它定义了从PKCS#1到PKCS#15的一系列标准。其中最常用的是PKCS#7、PKCS#12和PKCS#10。PKCS#7是消息请求语法,常用于数字签名和加密,PKCS#12是个人消息交换和打包语法,主要用于生成公钥和私钥。PKCS#10是证书请求语法。各种证书的后缀和转换操作过证书的朋友可能会被证书的后缀弄得眼花缭乱。一般来说,DER、CRT、CER、PEM证书都有后缀。DER表示证书的内容是用二进制编码的。PEM文件是一个文本文件,其内容以“-BEGIN-”、Base64编码字符开头。CRT和CER基本上是等价的。它们都是证书扩展和文本文件。不同的是CRT通常用于liunx和unix系统,而CER通常用于windows系统。而在windows系统中,CER文件会被MScryptoAPI命令识别,可以直接显示导入和/或查看证书内容的对话框。KEY文件主要用来保存PKCS#8标准的公钥和私钥。下面的命令可以用来查看文本证书的内容:opensslx509-incert.pem-text-nooutopensslx509-incert.cer-text-nooutopensslx509-incert.crt-text-noout下面的命令可以用于查看二进制证书内容:opensslx509-incert.der-informder-text-noout下面是PEM和DER的常见转换:PEMtoDERopensslx509-incert.crt-outformder-outcert。derDER到PEMopensslx509-incert.crt-informder-outformpem-outcert.Pemnetty启动SSL服务器。其实这个标题是错误的。netty中启动的服务器仍然是原来的服务器,只是对发送的消息进行了加密和解密。也就是说,增加了一个专用于SSL操作的Handler。netty中代表ssl处理器的类叫做SslHandler,它是SslContext项目类的内部类,所以我们只需要调用newHandler方法创建SslContext返回SslHandler即可。让服务端支持SSL代码:ChannelPipelinep=channel.pipeline();SslContextsslCtx=SslContextBuilder.forServer(...).build();p.addLast("ssl",sslCtx.newHandler(channel.alloc()));让客户端支持SSL代码:ChannelPipelinep=channel.pipeline();SslContextsslCtx=SslContextBuilder.forClient().build();p.addLast("ssl",sslCtx.newHandler(channel.alloc(),host,port));netty中实现SSL有两种方式。默认情况下,使用OpenSSL。如果OpenSSL不可用,则将使用JDK的实现。要创建SslContext,请调用SslContextBuilder.forServer或SslContextBuilder.forClient方法。这里我们以服务器为例,看看创建过程。SslContextBuilder有多个forServer方法,这里分析最简单的一个:}该方法接收两个参数,keyCertChainFile是一个PEM格式的X.509证书文件,keyFile是一个PKCS#8私钥文件。熟悉OpenSSL的童鞋应该都知道,使用openssl命令可以生成私钥文件和对应的自签名证书文件。具体的openssl操作可以查看我的其他文章,这里就不详细说明了。除了手动创建证书文件和私钥文件之外,如果您在开发环境中,您可能希望有一种非常简单的方法来创建证书和私钥文件。Netty为您提供了SelfSignedCertificate类。看这个类的名字就知道是一个自签名证书类,会在系统的temp文件夹下自动生成证书文件和私钥文件,所以不推荐在生产环境中使用这个类。默认情况下,此类将使用OpenJDK的X.509生成证书的私钥,如果不是,请改用BouncyCastle。在netty中启动SSL客户端还需要在客户端中创建一个支持SSL的handler。客户端的SslContext创建代码如下://ConfigureSSL。最终SslContextsslCtx=SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();在上面的代码中,我们使用InsecureTrustManagerFactory.INSTANCE作为trustManager。什么是信任管理器?当客户端和服务器建立SSL连接时,客户端需要验证服务器发送的证书的正确性。通常,这种验证是在CA服务器中进行的,但这需要一个真实的CA证书环境。所以在测试中,我们使用InsecureTrustManagerFactory,默认接受所有证书,忽略所有证书异常。当然,CA服务器不是必需的。客户端验证的目的是检查证书中的公钥是否与发送方的公钥一致。那么对于无法联网的环境或者自签名的环境,我们只需要在客户端验证证书中的指纹是否一致即可。Netty提供了一个FingerprintTrustManagerFactory类,可以验证证书中的指纹。该类中有一个fingerprints数组,用于存储安全授权的指纹信息。通过比对传入的证书和指纹,如果一致,则验证通过。使用openssl从证书中提取指纹的步骤如下:opensslx509-fingerprint-sha256-inmy_certificate.crt总结通过在客户端和服务器上设置SSLhandler,客户端和服务器之间的加密消息传输可以得以实现。本文示例可参考:learn-netty4本文已收录于http://www.flydean.com/12-netty-securechat/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!
