netty实现TLS/SSL双向加密认证

标签: netty  ssl  tls  加密解密  

 

示例工程及测试用的证书文件:https://download.csdn.net/download/zhangfls/12875187

1、双向加密认证首先要获取到证书,可以先自己生成证书用于测试(实际获取到的公网证书使用方式其实差不多

(1)可以通过openssl生成证书

(2)首先要生成一份CA根证书,再由该证书生成服务器和客户端的证书

(3)完成基本的SSL/TLS服务器和客户端的双向加密通讯,一共需要生成5份证书

    ①CA证书

    ②服务器证书

    ③服务器**

    ④客户端证书

    ⑤客户端**

(4)、一般证书有多种格式,这里我们用pem格式做示例(linux系统常用)

 

2、假设我们已经配置了证书,同时配置好了一个简单的nettyTCP连接的客户端和服务器,下面则需要重新配置netty服务器与客户端的SSL管道
(1)、配置netty的SSL可以通过添加pipeline的方式完成,将管道配置在ChannelInitializer实现类的最前面即可

public class MyChannelInitializer extends ChannelInitializer<SocketChannel> {

    private SslContext sslContext;

    public MyChannelInitializer(SslContext sslContext) {
        this.sslContext = sslContext;
    }

    @Override
    protected void initChannel(SocketChannel channel) {

        // 添加SSL安装验证
        channel.pipeline().addFirst(sslContext.newHandler(channel.alloc()));
        //直接解析原始HEX字节
        channel.pipeline().addLast(new StringEncoder(StandardCharsets.ISO_8859_1));
        //自定义解析数据handler
        channel.pipeline().addLast(new MyServerHandler());
        channel.pipeline().addLast(new ByteArrayEncoder());
    }
}

 

(2)包含证书信息的SslContext可以由SslContextBuilder来生成,可以分别生成客户端及服务器的SSL验证protocol。例如下面的certChainFile 为客户端证书,keyFile为客户端**,rootFile为CA根证书,服务器的证书配置同理

        //引入SSL安全验证
        File certChainFile = new File("D:\\OpenSSL-Win64\\bin\\client\\client-cert.pem");
        File keyFile = new File("D:\\OpenSSL-Win64\\bin\\client\\client-key.pem");
        File rootFile = new File("D:\\OpenSSL-Win64\\bin\\ca\\ca-cert.pem");
        
        SslContext sslCtx = SslContextBuilder.forClient().keyManager(certChainFile, keyFile).trustManager(rootFile).build();

 

3、一般做双向验证,服务器端可能还会需要客户端证书的详细信息,来确认客户端的身份。可以通过在连接握手完成时,读取SSLSession的信息,来获取到客户端证书的详细信息,如下:

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
                new GenericFutureListener<Future<Channel>>() {
                    @Override
                    public void operationComplete(Future<Channel> future) throws Exception {
                        if(future.isSuccess()){
                            System.out.println("握手成功");

                            SSLSession ss =  ctx.pipeline().get(SslHandler.class).engine().getSession();
                            System.out.println("cipherSuite:"+ss.getCipherSuite());
                            X509Certificate cert = ss.getPeerCertificateChain()[0];
                            String info = null;
                            // 获得证书版本
                            info = String.valueOf(cert.getVersion());
                            System.out.println("证书版本:" + info);
                            // 获得证书***
                            info = cert.getSerialNumber().toString(16);
                            System.out.println("证书***:" + info);
                            // 获得证书有效期
                            Date beforedate = cert.getNotBefore();
                            info = new SimpleDateFormat("yyyy/MM/dd").format(beforedate);
                            System.out.println("证书生效日期:" + info);
                            Date afterdate = (Date) cert.getNotAfter();
                            info = new SimpleDateFormat("yyyy/MM/dd").format(afterdate);
                            System.out.println("证书失效日期:" + info);
                            // 获得证书主体信息
                            info = cert.getSubjectDN().getName();
                            System.out.println("证书拥有者:" + info);
                            // 获得证书颁发者信息
                            info = cert.getIssuerDN().getName();
                            System.out.println("证书颁发者:" + info);
                            // 获得证书签名算法名称
                            info = cert.getSigAlgName();
                            System.out.println("证书签名算法:" + info);

                        }else{
                            System.out.println("握手失败");
                        }
                    }
                });

        SocketChannel channel = (SocketChannel) ctx.channel();
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" conn:");
        System.out.println("IP:" + channel.localAddress().getHostString());
        System.out.println("Port:" + channel.localAddress().getPort());
    }

4、配置完成后,先启动服务器,再启动客户端,可以看到连接建立成功



版权声明:本文为zhangfls原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangfls/article/details/108712415

智能推荐

邮件推送SSL/TLS加密连接

邮件服务器使用的是未加密的连接,使用未加密网络发送敏感信息可能会被恶意攻击者通过拦截网络通信读取并修改信息。邮件发送加密通道分为SSL和TLS两种方式,SSL“安全套接层”协议,TLS“安全传输层”协议,都属于是加密协议(详细介绍 点击这里),加密模式下各协议端口也发生变化,不同的邮箱可能端口不同,基本上 stmp非SSL默认端口25   ...

第三方库PNChart的使用

PNChart 是一个强大的带动画的图表库   要是用这个库可以使用pods,也可以直接将库导入项目中,必须引入"PNChart.h"头文件   下面我们来看一下代码!      转载于:https://www.cnblogs.com/aeronfay/articles/4929223.html...

LeetCode刷题笔记(10)-BFS广度优先搜索

LeetCode刷题笔记(10)-BFS广度优先搜索 127、单词接龙 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: 每次转换只能改变一个字母。 转换过程中的中间单词必须是字典中的单词。 输入: beginWord = “hit”, endWord = &ldqu...

线性筛选素数的方法及基于线性筛选素数的欧拉函数筛选莫比乌斯函数筛选

欧拉筛法线性求素数 回忆一下经典的埃式筛法求素数。时间复杂度是为O(nloglogn)(我之前一直以为是O(n))O(nloglogn)(我之前一直以为是O(n)) 显然,当一个数是素数的时候,那么他的倍数肯定是合数,筛选标记即可 我们来举个列子 筛选2-10的素数 首先2是素数,然后把其倍数删去,我们标记下删去的次数用一个斜杠表示删去了一次 之后3是素数,继续删去倍数,这个时候发现6被重复删去两...

JEECG 页面多个用户选择器只显示最后一个

在一个页面当中,我们可能会需要有多个的用户选择器进行快速的录入,此时会发现所有的输入都会在最后一个用户选择器的地方显示 查看页面代码当中的ID也是不一致: 查看通过标签生成之后的源码,可以发现所有的用户选择器都会生成一个 点击输入框调用的js方法都是一样的,看到这里也就可以明白为什么都是只有最后一个用户选择输入框当中有数据了。 因此我们对后台当中标签代码生成部分进行改造,让其支持多个用户选择器: ...

猜你喜欢

力扣47 全排列ii 回溯加剪枝

 这题难点在于先排序,然后重复的数字112 used[i-1]= fase 代表之前我用过了,就是我俩 1前面的用过了现在这一个我就直接跳过去    ...

arp协议

arp协议叫做地址解析协议,通常与ip地址共同使用,将ip地址转换成硬件地址(MAC地址)。arp既可以放在网络层,也可以放在数据链路层,因为它做了两层的工作。 当一个主机向另一个主机发送数据报时,通过arp协议,向局域网中发送arp请求,所有在局域网中的主机都可以收到,但会在网络层丢弃,只有一台符合目的ip的主机会发送给源主机arp响应包含自己mac地址,因此源主机就可以向目的主机发送报文。 l...

模拟登陆改版后的知乎(最新版)

今天,想着看看视频,把模拟登陆这一块学习学习,以后弄把梯子,去爬爬FaceBook什么的。就拿知乎练练手吧,可曾想,知乎竟然改版了!!之前的教程书籍对现在的知乎来说,都是扯淡,连页面都找不到了。下面一起谈谈改版后的纸糊的模拟登陆吧。 页面分析 抓包 首先,打开页面:https://www.zhihu.com/signup?next=%2F(登录网址都变了…),F12,输入账号密码(记...

干货分享——比微信域名防封防举报更牛逼的防封方案

从微信兴起到现在,微信的流量就一直居高不下,在淘宝时代和传统的电商时代,只要把广告打出去,别人通过搜索就可以找到我们,所以,移动互联网的到来,在微信爆棚的今天,都想在微信里面推广自己的产品,借力微信,达到客户沉淀,营销宣传,传播影响的目的,可以由于微信种种机制,有人腾讯要维护自身的利益,也有人说是微信要营造一个健康的生态圈,种种限制,比如分享次数过多,域名会被微信拦截屏蔽封杀,还比如微信中的链接不...

mysql的事务提交(java)

个人理解的一个事务:是一个Connection一系列的操作过程,如果是两个Connection连接在操作,那就是两个事务。 事务的前提:数据库的存储引擎是innodb。 事务的目的:保证数据的安全性。 事务安全:  1.自动提交事务:每执行一条sql语句,就同步到数据库中。  2.手动提交事务:执行一系列的sql语句后一起同步到数据库中。 事务的四大特性:  A(at...