手把手教你为基于netty的im生成自签名ssl/tls证书 -凯发k8网页登录

我的最新工程mobileimsdk:http://git.oschina.net/jackjiang/mobileimsdk
posts - 336, comments - 13, trackbacks - 0, articles - 0

对于im聊天应用来说,为了提升安全性,对聊天消息加密是常规操作。

众所周之,是高性能的java nio网络通信框架,因而用netty来写im是再正常不过了。网上关于为netty生成、以及使用ssl/tls证书的文章有很多,但由于各种原因,生成的证书要么是netty中无法读取和使用,要么是代码不全或不具体导致根本配不通ssl/tls加密。

正好这段时间专门为  生成了一套测试证书,顺手把这个过程记录了下来,分享给大家。

本文要分享的是如何使用openssl生成在基于netty的im中真正可用的ssl/tls证书,内容包括:证书的创建、创建过程中的注意点,以及在server端、android端、ios端、java桌面端、h5端使用证书的代码范例。

注:对于那些付费购买了第3方权威ca机构签发的证书,他们都有相应的使用文档,这就没什么好说的。本文里的证书指的是不需要花钱的自签名证书。

学习交流:

- 移动端im开发入门文章:《》

- 开源im框架源码:()

(本文已同步发布于:)

► 如果你对im系统毫无概念,建议先阅读《》系列文章,通俗易懂,适合小白。

► 如果你想系统学习im开发相关的理论知识,比如网格编程、im架构设计等,建议先阅读《》。

► 如果你不了解netty是什么,建议阅读以下几篇netty的基础入门好文章:

  • 1)
  • 2)
  • 3)

► 如果你已掌握im理论知识,同时也对netty基本掌握,正准备动手实战,则可以阅读《》和《》这个系列文章,有各种入门级实战代码,图文并茂,适合学习。

► 如果你对im、netty已基本上手,但对im安全方面的技术概念有点理不清,建议必读《》。

netty是一个java nio技术的开源异步事件驱动的网络编程框架,用于快速开发可维护的高性能协议服务器和客户端。往通俗了讲,可以将netty理解为:一个将java nio进行了大量封装,并大大降低java nio使用难度和上手门槛的超牛逼框架。(引用自《》)

ps:限于篇幅,对于netty方面的入门知识就不再赘述,如有必要,请仔细跟着本文第二节“里有关netty的文章进行阅读。

是一个开放源代码的软件库,应用程序可以使用这个包来进行安全通信,它包括代码、脚本、配置和过程的集合。其主要库是以 c 语言所写成,实现了基本的加密功能,实现了 ssl 与 tls 协议。openssl整个软件包大概可以分成三个主要功能部分:ssl协议库、应用程序、密码算法库。

ps:openssl的介绍就点到为止,如有兴趣,可仔细阅读《》。

1)方法一:可以从openssl的github仓库下载源码自行编译(),对于一般使用者来说,自已编译着实有点麻烦,不推荐这么玩。

2)方法一:也可以从这个网站下载第3方编译好的openssl安装程序(),这样上手简单快捷。具体可以参考《》这篇文章。

3)方法一:也可以直接用下面附件里的安装程序(这是我一直用的版本,版本较老,有兴趣可直接下载使用):

  (874.97 kb , 下载次数: 1 , 售价: 1 金币)

4)解决 “openssl.cnf找不到” 的问题:如果你安装好openssl后,使用时报“openssl.cnf找不到”或“计算机缺少openssl.cnf”等之类错误提示,可以下载下面这个 openssl.cnf文件。

openssl.cnf 文件附件下载:

  (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.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.1概述

本节将为你演示如何在基于netty的im中使用上节中生成的证书。

为了让示例代码更具实战意义,本节的示例代码将引用的是开源im框架  的源码,如果有兴趣深入学习,可以从下面的开源仓库中下载到mobileimsdk的完整源码。

  • 1)github.com 托管地址:
  • 2)码云gitee托管地址:

7.2基于netty的im服务端如何开启ssl/tls

首先将上节中生成的证书,放置到你的im服务端磁盘目录下。以下截图和示例代码以的开源代码为例。

我们可以将证书放到这个位置:

使用证书的示例代码片段:完整代码详见 )

/**

 * 创建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:如果你想自已动手完整运行一下,可以阅读《》。

接下来的内容,我们将实现客户端连接到使用ssl/tls证书的netty im服务端。

7.3android端如何开启ssl/tls

因为服务端已经开启了ssl/tls加密,我们在开发im的客户端时,该如何启用ssl/tls呢(否则你未开启ssl/tls的客户端肯定是连不上你的服务端的)?

这里为了方便示例,我们同样以 的android端开源代码为例。

android端开启ssl/tls加密的示例代码片段:(完整代码详见 )

/**

 * 创建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:如果你想自已动手完整运行一下,可以阅读《》。

7.4ios端如何开启ssl/tls

同样的,ios端该如何开启ssl/tls呢?

这里我们依然以 的ios端开源代码为例(mobileimsdk的ios使用的是  网络库,如果你也是用的它,就可以直接参考了,因为开启了ssl/tls的cocoaasyncsocket代码跟未开启加密的代码用法差异较多,且这方面可以参考的资料较少)。

ios端开启ssl/tls加密的示例代码片段:(完整代码详见 )

/**

 * 当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:如果你想自已动手完整运行一下,可以阅读《》。

7.5java桌面端如何开启ssl/tls

java桌面端开启ssl/tls的代码跟android端是一样。我们同样以 的开源代码为例。

java桌面端开启ssl/tls加密的示例代码片段:完整代码详见 

/**

 * 创建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:如果你想自已动手完整运行一下,可以阅读《》。

7.6h5端如何开启ssl/tls

我这里说的h5端,指的是能支持标准html5端的pc浏览器端、手机移动端内嵌的web引擎等场景。

h5端能开启ssl/tls有两个前提:

  • 1)第3方ca机构签发的ssl/tls证书(这条是关键,不然浏览器因安全原因会阻止websocket连接的建立);
  • 2)基于netty的im服务端已开启ssl/tls(见本章“”)。

满足以上两点后,h5端什么代码都不需改动,只需将请求url由“ws”改成“wss”:

[1] 

[2] 

[3] 

[4] 

[5] 

[6] 

[7] 

[8] 

[9] 

(本文已同步发布于:)



作者: (点击作者姓名进入github)
出处:
交流:欢迎加入即时通讯开发交流群
讨论:
jack jiang同时是和的作者,可前往下载交流。
本博文 欢迎转载,转载请注明出处(也可前往 找到我)。


只有注册用户后才能发表评论。


网站导航:
              
 
jack jiang的 mail: jb2011@163.com, 联系qq: 413980957, 微信: hellojackjiang
网站地图