手把手教你为基于Netty的IM生成自签名SSL/TLS证书
1、引言
对于IM聊天应用来说,为了提升安全性,对聊天消息加密是常规操作。
众所周之,Netty是高性能的Java NIO网络通信框架,因而用Netty来写IM是再正常不过了。网上关于为Netty生成、以及使用SSL/TLS证书的文章有很多,但由于各种原因,生成的证书要么是Netty中无法读取和使用,要么是代码不全或不具体导致根本配不通SSL/TLS加密。
正好这段时间专门为 MobileIMSDK 生成了一套测试证书,顺手把这个过程记录了下来,分享给大家。
本文要分享的是如何使用OpenSSL生成在基于Netty的IM中真正可用的SSL/TLS证书,内容包括:证书的创建、创建过程中的注意点,以及在Server端、Android端、iOS端、Java桌面端、H5端使用证书的代码范例。
注:对于那些付费购买了第3方权威CA机构签发的证书,他们都有相应的使用文档,这就没什么好说的。本文里的证书指的是不需要花钱的自签名证书。
学习交流:
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》
- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK(备用地址点此)
(本文已同步发布于:http://www.52im.net/thread-4142-1-1.html)
2、知识准备
► 如果你对IM系统毫无概念,建议先阅读《零基础IM开发入门(一):什么是IM系统?》系列文章,通俗易懂,适合小白。
► 如果你想系统学习IM开发相关的理论知识,比如网格编程、IM架构设计等,建议先阅读《新手入门一篇就够:从零开发移动端IM》。
► 如果你不了解Netty是什么,建议阅读以下几篇Netty的基础入门好文章:
- 1)新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析
- 2)写给初学者:Java高性能NIO框架Netty的学习方法和进阶策略
- 3)史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战
► 如果你已掌握IM理论知识,同时也对Netty基本掌握,正准备动手实战,则可以阅读《基于Netty,从零开发IM》和《跟着源码学IM》这个系列文章,有各种入门级实战代码,图文并茂,适合学习。
► 如果你对IM、Netty已基本上手,但对IM安全方面的技术概念有点理不清,建议必读《基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等》。
3、什么是Netty
Netty是一个Java NIO技术的开源异步事件驱动的网络编程框架,用于快速开发可维护的高性能协议服务器和客户端。往通俗了讲,可以将Netty理解为:一个将Java NIO进行了大量封装,并大大降低Java NIO使用难度和上手门槛的超牛逼框架。(引用自《史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战》)
PS:限于篇幅,对于Netty方面的入门知识就不再赘述,如有必要,请仔细跟着本文第二节“2、知识准备”里有关Netty的文章进行阅读。
4、什么是OpenSSL
OpenSSL是一个开放源代码的软件库,应用程序可以使用这个包来进行安全通信,它包括代码、脚本、配置和过程的集合。其主要库是以 C 语言所写成,实现了基本的加密功能,实现了 SSL 与 TLS 协议。OpenSSL整个软件包大概可以分成三个主要功能部分:SSL协议库、应用程序、密码算法库。
PS:OpenSSL的介绍就点到为止,如有兴趣,可仔细阅读《基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等》。
5、下载和安装OpenSSL
1)方法一:可以从OpenSSL的Github仓库下载源码自行编译(源码下载地址),对于一般使用者来说,自已编译着实有点麻烦,不推荐这么玩。
2)方法一:也可以从这个网站下载第3方编译好的OpenSSL安装程序(安装程序下载地址),这样上手简单快捷。具体可以参考《openssl安装教程(windows7系统,超详细)》这篇文章。
3)方法一:也可以直接用下面附件里的安装程序(这是我一直用的版本,版本较老,有兴趣可直接下载使用):
Openssl-windows-0.9.8k(52im.net).rar (874.97 KB , 下载次数: 1 , 售价: 1 金币)
4)解决 “openssl.cnf找不到” 的问题:如果你安装好OpenSSL后,使用时报“openssl.cnf找不到”或“计算机缺少openssl.cnf”等之类错误提示,可以下载下面这个 openssl.cnf文件。
openssl.cnf 文件附件下载:
openssl_conf(52im.net).rar (4.63 KB , 下载次数: 1 , 售价: 1 金币)
openssl.cnf 文件解压缩后:
openssl.cnf文件配置使用:
以下是 openssl.cnf 文件的配置使用命令:(以我的安装目录为例)
C:\Openssl-windows-0.9.8k-out32dll>set OPENSSL_CONF=c:/WINDOWS/system32/openssl.cnf
准备就绪,接下来我们就可以开始生成SSL/TLS证书了!
6、生成Netty可用的SSL/TLS证书
6.1概述
经过实践,生成Netty可用的SSL/TLS证书需要4步:
- 1)创建私钥证书;
- 2)将私钥格式转成pk8;
- 3)创建证书请求;
- 4)生成公钥证书。
接下来,跟着本节内容,一步步使用OpenSSL生成一个真正能在Netty中能使用的自签名证书。
6.2第一步:创建私钥证书
在CMD控制台下执行如下指令:(记得手动创建 netty 目录)
openssl genrsa -des3 -out netty/netty-key.pem 1024
提示:以上指令中,如无“-des3”参数,则Netty的代码中使用时将报“File does not contain valid private key”等错误(如下图所示)。
6.3第二步:将私钥格式转成pk8
在CMD控制台下执行如下指令:
openssl pkcs8 -innetty/netty-key2.pem -topk8 -out netty/netty-key2.pk8
提示1:如不转pk8格式,则Netty的代码中使用时会报以下错误:
提示2:如代码中不为key加入密码,则Netty的代码中使用时会报以下错误:
提示3:Netty的代码中使用时要加入上方生成Key证书时的密码即可:
6.4第三步:创建证书请求
在CMD控制台下执行如下指令:
openssl req -new -out netty/netty-req2.csr -key netty/netty-key2.pem
提示:经上指令中,Common Name指明的是证书绑定的域名,你可以用域名或ip,本次生成用了子域名。
6.5第四步:生成公钥证书
在CMD控制台下执行如下指令:
openssl x509 -req -inca/ca-req2.csr -out netty/netty-cert2.crt -signkey netty/netty-key2.pem -days 3650
提示:out 参数生成的是.crt,而在前面的是.pem,这只是扩展名区别,内容都一样。
6.6最终成果
至此,我们已经为Netty创建好了证书,接下来的章节,就是分享如何读取和使用这些证书的。
7、实战代码
7.1概述
本节将为你演示如何在基于Netty的IM中使用上节中生成的证书。
为了让示例代码更具实战意义,本节的示例代码将引用的是开源IM框架MobileIMSDK 的源码,如果有兴趣深入学习,可以从下面的开源仓库中下载到MobileIMSDK的完整源码。
- 1)GitHub.com 托管地址:https://github.com/JackJiang2011/MobileIMSDK
- 2)码云gitee托管地址:https://gitee.com/jackjiang/MobileIMSDK
7.2基于Netty的IM服务端如何开启SSL/TLS
首先将上节中生成的证书,放置到你的IM服务端磁盘目录下。以下截图和示例代码以MobileIMSDK的开源代码为例。
我们可以将证书放到这个位置:
使用证书的示例代码片段:(完整代码详见 ServerLauncherImpl.java)
/**
* 创建SslContext对象,用于开启SSL/TLS加密传输。
*
* @return 如果成功创建则返回SslContext对象,否则返回null
*/
privatestaticSslContext createSslContext() {
try{
// 证书文件
InputStream certChainFile = ServerLauncherImpl.class.getResourceAsStream("certs/netty-cert2.crt");
// 私钥文件(注意:Netty只支持.pk8格式)
InputStream keyFile = ServerLauncherImpl.class.getResourceAsStream("certs/netty-key2.pk8");
// 私钥密码
String keyPassword = "123456";
// 生成SslContext对象(为了方便理解,此处使用的是单向认证)
SslContext sslCtx = SslContextBuilder.forServer(certChainFile, keyFile, keyPassword).clientAuth(ClientAuth.NONE).build();
returnsslCtx;
} catch(Exception e) {
logger.warn("createSslContext()时出错了,原因:"+e.getMessage(), e);
}
returnnull;
}
PS:如果你想自已动手完整运行一下,可以阅读《MobileIMSDK的Demo使用帮助:Server端》。
接下来的内容,我们将实现客户端连接到使用SSL/TLS证书的Netty IM服务端。
7.3Android端如何开启SSL/TLS
因为服务端已经开启了SSL/TLS加密,我们在开发IM的客户端时,该如何启用SSL/TLS呢(否则你未开启SSL/TLS的客户端肯定是连不上你的服务端的)?
这里为了方便示例,我们同样以 MobileIMSDK的Android端开源代码为例。
Android端开启SSL/TLS加密的示例代码片段:(完整代码详见 IMClientManager.java)
/**
* 创建SslContext对象,用于开启SSL/TLS加密传输。
*
* @return 如果成功创建则返回SslContext对象,否则返回null
*/
publicSslContext createSslContext() {
SslContext sslContext = null;
try{
sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
Log.d(TAG, "【IMCORE-TCP】已开启SSL/TLS加密(单向认证),且sslContext创建成功。");
} catch(Exception e) {
Log.w(TAG, "【IMCORE-TCP】创建sslContext时出错,原因是:"+ e.getMessage(), e);
}
returnsslContext;
}
PS:如果你想自已动手完整运行一下,可以阅读《MobileIMSDK的Demo使用帮助:Android版》。
7.4iOS端如何开启SSL/TLS
同样的,iOS端该如何开启SSL/TLS呢?
这里我们依然以 MobileIMSDK的iOS端开源代码为例(MobileIMSDK的iOS使用的是 CocoaAsyncSocket 网络库,如果你也是用的它,就可以直接参考了,因为开启了SSL/TLS的CocoaAsyncSocket代码跟未开启加密的代码用法差异较多,且这方面可以参考的资料较少)。
iOS端开启SSL/TLS加密的示例代码片段:(完整代码详见 LocalSocketProvider.m)
/**
* 当socket已经完整连接并准备好读和写数据时,将调用此方法。
*/
- (void)socket:(MBGCDAsyncSocket *)socket didConnectToHost:(NSString*)host port:(uint16_t)port
{
if([ClientCoreSDK isENABLED_DEBUG])
NSLog(@"【IMCORE-TCP-SOCKET】成收到的了TCP的connect反馈, isConnected? %d、已开启ssl加密? %d", [socket isConnected], [ClientCoreSDK isSSL]);
// 如果未开启SSL加密传输,则正常进入连接完成后的代码逻辑
if(![ClientCoreSDK isSSL]) {
[selfwhenDidConnect:socket];
}
// 如果已开启SSL加密传输,则需要在回调中调用startTLS方法,以便实现跟服务端的SSL握手过程,
// 如果ssl握手成功,则会通过 socketDidSecure: 回调通知开发者
else{
// 配置 SSL/TLS 设置信息
NSMutableDictionary*settings = [NSMutableDictionarydictionaryWithCapacity:3];
// 允许自签名证书手动验证
[settings setObject:@YESforKey:GCDAsyncSocketManuallyEvaluateTrust];
// 经测试,本项不设置并不影响SSL的启用
// [settings setObject:@"此处填服务器IP地址" forKey:GCDAsyncSocketSSLPeerName];
// 如果不是自签名证书,而是权威证书颁发机构注册申请的证书,这个settings字典可不传(将使用GCDAsyncSocket的默认配置)
[socket startTLS:settings];
}
}
/**
* 当SSL握手成功后(也就是上方调用startSSL:方法后),将调用此方法。
*/
- (void)socketDidSecure:(MBGCDAsyncSocket *)socket
{
[selfwhenDidConnect:socket];
}
/**
* Allows a socket delegate to hook into the TLS handshake and manually validate the peer it's connecting to.
*/
- (void)socket:(MBGCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void(^)(BOOLshouldTrustPeer))completionHandler
{
NSLog(@"【IMCORE-TCP-SOCKET】didReceiveTrust...");
// 以下没有做更复杂的ssl证书验证逻辑,如您需要实现更强大的双向认证等逻辑,可以参考这里:
// [url=https://github.com/FuangCao/cavan/blob/338ca8c09d6c78c5b38b95c6ffe994241afcc96e/xcode/TestSSL/TestSSL/ViewController.m]https://github.com/FuangCao/cava ... SL/ViewController.m[/url]
if(completionHandler) {
completionHandler(YES);
}
}
说明:CocoaAsyncSocket中开启SSL/TLS并不像Android和Java中那么简单,它不只是几行代码的事,而是整个数据读取逻辑的变化。
PS:如果你想自已动手完整运行一下,可以阅读《MobileIMSDK的Demo使用帮助:iOS版》。
7.5Java桌面端如何开启SSL/TLS
Java桌面端开启SSL/TLS的代码跟Android端是一样。我们同样以 MobileIMSDK的Java端开源代码为例。
Java桌面端开启SSL/TLS加密的示例代码片段:(完整代码详见 IMClientManager.java)
/**
* 创建SslContext对象,用于开启SSL/TLS加密传输。
*
* @return 如果成功创建则返回SslContext对象,否则返回null
*/
publicSslContext createSslContext() {
SslContext sslContext = null;
try{
sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
Log.d(TAG, "【IMCORE-TCP】已开启SSL/TLS加密(单向认证),且sslContext创建成功。");
} catch(Exception e) {
Log.w(TAG, "【IMCORE-TCP】创建sslContext时出错,原因是:"+ e.getMessage(), e);
}
returnsslContext;
}
PS:如果你想自已动手完整运行一下,可以阅读《MobileIMSDK的Demo使用帮助:Java版》。
7.6H5端如何开启SSL/TLS
我这里说的H5端,指的是能支持标准HTML5端WebSocket协议的PC浏览器端、手机移动端内嵌的Web引擎等场景。
H5端能开启SSL/TLS有两个前提:
- 1)第3方CA机构签发的SSL/TLS证书(这条是关键,不然浏览器因安全原因会阻止WebSocket连接的建立);
- 2)基于Netty的IM服务端已开启SSL/TLS(见本章“7.2 基于Netty的IM服务端如何开启SSL/TLS”)。
满足以上两点后,H5端什么代码都不需改动,只需将请求url由“ws”改成“wss”:
8、参考资料
[2] 史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战
[3] 基于Netty,从零开发IM
[4] 基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等
[7] 探讨组合加密算法在IM中的应用
[8] openssl安装教程(windows7系统,超详细)
(本文已同步发布于:http://www.52im.net/thread-4142-1-1.html)
手把手教你为基于Netty的IM生成自签名SSL/TLS证书的更多相关文章
- 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接
本文原作者:“水晶虾饺”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.引言 好多小白初次接触即时通讯(比如:IM或者消息推送应用)时,总是不 ...
- 手把手教你写基于C++ Winsock的图片下载的网络爬虫
手把手教你写基于C++ Winsock的图片下载的网络爬虫 先来说一下主要的技术点: 1. 输入起始网址,使用ssacnf函数解析出主机号和路径(仅处理http协议网址) 2. 使用socket套接字 ...
- 庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境
庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境 一.介绍 说起微服务架构来,有一个环节是少不了的,那就是CI/CD持续集成的环境.当然,搭建CI/CD环境的工具很多, ...
- Netty入门(七)使用SSL/TLS加密Netty程序
为了支持 SSL/TLS,Java 提供了 javax.net.ssl API 的类 SslContext 和 SslEngine 使它相对简单的实现解密和加密.Netty 利用该 API 实现了 C ...
- 手把手教你学会 基于JWT的单点登录
最近我们组要给负责的一个管理系统 A 集成另外一个系统 B,为了让用户使用更加便捷,避免多个系统重复登录,希望能够达到这样的效果--用户只需登录一次就能够在这两个系统中进行操作.很明显这就是单点登 ...
- 满满干货!手把手教你实现基于eTS的分布式计算器
最近收到很多小伙伴反馈,想基于扩展的TS语言(eTS)进行HarmonyOS应用开发,但是不知道代码该从何处写起,从0到1的过程让新手们抓狂. 本期我们将带来"分布式计算器"的开发 ...
- 手把手教你基于Netty实现一个基础的RPC框架(通俗易懂)
阅读这篇文章之前,建议先阅读和这篇文章关联的内容. [1]详细剖析分布式微服务架构下网络通信的底层实现原理(图解) [2][年薪60W的技巧]工作了5年,你真的理解Netty以及为什么要用吗?(深度干 ...
- Delphi - 手把手教你基于D7+Access常用管理系统架构的设计与实现 (更新中)
前言 从事软件开发工作好多年了,学的越深入越觉得自己无知,所以还是要对知识保持敬畏之心,活到老,学到老! 健身和代码一样都不能少,身体是革命的本钱,特别是我们这种高危工种,所以小伙伴们运动起来!有没有 ...
- 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)
本文由“yuanrw”分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读,但最好有一定的网络 ...
- 自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)
本文由作者FreddyChen原创分享,为了更好的体现文章价值,引用时有少许改动,感谢原作者. 1.写在前面 一直想写一篇关于im即时通讯分享的文章,无奈工作太忙,很难抽出时间.今天终于从公司离职了, ...
随机推荐
- .NET 6使用ImageSharp给图片添加水印
.NET 6 中,使用System.Drawing操作图片,生成解决方案或打包的时候,会有警告,意思是System.Drawing仅在 'windows' 上受支持.微软官方的解释是: Syste ...
- windows GO语言环境配置
目录 GO语言下载 安装goland go目录简介 配置gopath goland里添加goroot和gopath GO语言下载 参考教程:https://www.cnblogs.com/Domini ...
- Vue DevUI v1.4 版本发布:从体验、效率、质量三个方面做了全方位的优化🎉
2022年9月1日,我们正式宣布 Vue DevUI 组件库发布 v1.0 版本. Vue DevUI 1.0 正式发布 经过100多天的持续迭代,我们正式发布 v1.4.0 版本,共新增: 11位贡 ...
- Python报SyntaxError: Missing parentheses in call to ‘print’. Did you mean print()
SyntaxError: Missing parentheses in call to 'print'. Did you mean print()原因:python2.X版本与python3.X版本输 ...
- VSCTF的Recovery
题目如下: from random import randint from base64 import b64encode def validate(password: str) -> bool ...
- 【转载】SQL 2012以上版本分页查询更简单
2012以上版本分页查询更简单 注意:以下都是先执行排序,再取行数据 select* from t_workers order by worker_id desc offset 3 rows -- ...
- Python实现单项链表
单向链表 单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域.这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值. 表元素域ele ...
- session取不到值
今天鼓捣项目时出现了一个问题 项目重启后,设置session值后,第一次请求经过过滤器时 session取不到值,导致被拦截 经过半天的研究,终于...我请教了别人 把代码给了朋友,在朋友一段时间的琢 ...
- ArcGIS工具 - 按线分割面
功能说明 在ArcGIS数据处理过程中,有时需要沿线把面要素分割开,可以使用高级编辑中的分割面(Cut Polygon)工具.那么,如果要用线图层分割面图层该怎么办呢?为源GIS为您开发了一个自定义模 ...
- 用 Python 脚本实现电脑唤醒后自动拍照 截屏并发邮件通知
背景 背景是这样的, 我的家里台式机常年 休眠, 并配置了 Wake On Lan (WOL) 方便远程唤醒并使用. 但是我发现, 偶尔台式机会被其他情况唤醒, 这时候我并不知道, 结果白白运行了好几 ...