Jack Jiang

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

          導航

          公告


            ① 即時通訊開發社區
            地址: 52im.net
            專業的資料、社區

            ② 關注我的公眾號:

            讓技術不再封閉

            ③ 我的Github
            地址: 點此進入
            好代碼,與大家分享
          <2023年2月>
          2930311234
          567891011
          12131415161718
          19202122232425
          2627281234
          567891011

          常用鏈接

          留言簿(289)

          隨筆檔案

          文章檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          60天內閱讀排行

          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機構簽發的證書,他們都有相應的使用文檔,這就沒什么好說的。本文里的證書指的是不需要花錢的自簽名證書。

          學習交流:

          (本文已同步發布于:http://www.52im.net/thread-4142-1-1.html

          2、知識準備

          ► 如果你對IM系統毫無概念,建議先閱讀《零基礎IM開發入門(一):什么是IM系統?》系列文章,通俗易懂,適合小白。

          ► 如果你想系統學習IM開發相關的理論知識,比如網格編程、IM架構設計等,建議先閱讀《新手入門一篇就夠:從零開發移動端IM》。

          ► 如果你不了解Netty是什么,建議閱讀以下幾篇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的完整源碼。

          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端是一樣。我們同樣以 MobileIMSDKJava端開源代碼為例。

          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、參考資料

          [1] MobileIMSDK開源工程源碼

          [2] 史上最通俗Netty框架入門長文:基本介紹、環境搭建、動手實戰

          [3] 基于Netty,從零開發IM

          [4] 基于Netty的IM聊天加密技術學習:一文理清常見的加密概念、術語等

          [5] IM聊天系統安全手段之通信連接層加密技術

          [6] 通俗易懂:一篇掌握即時通訊的消息傳輸安全原理

          [7] 探討組合加密算法在IM中的應用

          [8] openssl安裝教程(windows7系統,超詳細)

          [9] WebSocket從入門到精通,半小時就夠!

          (本文已同步發布于:http://www.52im.net/thread-4142-1-1.html



          作者:Jack Jiang (點擊作者姓名進入Github)
          出處:http://www.52im.net/space-uid-1.html
          交流:歡迎加入即時通訊開發交流群 215891622
          討論:http://www.52im.net/
          Jack Jiang同時是【原創Java Swing外觀工程BeautyEye】【輕量級移動端即時通訊框架MobileIMSDK】的作者,可前往下載交流。
          本博文 歡迎轉載,轉載請注明出處(也可前往 我的52im.net 找到我)。


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          Jack Jiang的 Mail: jb2011@163.com, 聯系QQ: 413980957, 微信: hellojackjiang
          主站蜘蛛池模板: 周口市| 社旗县| 南乐县| 庄河市| 苏尼特右旗| 本溪| 合阳县| 收藏| 云南省| 台湾省| 东港市| 惠安县| 临朐县| 大埔区| 延川县| 乌鲁木齐市| 辽阳县| 霍邱县| 北川| 筠连县| 淄博市| 砀山县| 方山县| 油尖旺区| 临夏县| 广东省| 广灵县| 海口市| 古田县| 天等县| 内黄县| 托里县| 册亨县| 陆河县| 湾仔区| 辽阳市| 于都县| 安仁县| 湛江市| 凤庆县| 玛多县|