Jack Jiang

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

          1、前言

          可能有初學者會問,即時通訊應用的通信安全,不就是對Socket長連接進行SSL/TLS加密這些知識嗎,干嗎要理解HTTPS協議呢。

          這其實是個誤解:當今主流的移動端IM數據通信,總結下來無外乎就是長連接+短連接的方式,長連接就是眾所周之的TCP、UDP、WebSocket(WebSocket的本質還是TCP),而短連接就是HTTP/HTTPS了。即時通訊IM應用中,短連接的安全跟長連接相比,同樣很重要。市面上的主流短連接通信方式,都已逐步從HTTP過渡到HTTPS了(iOS上的應用就更徹底了,蘋果直接強制要求使用HTTPS協議,否則不允許上架APP Store,詳見《蘋果即將強制實施 ATS,你的APP準備好切換到HTTPS了嗎?》。不過,鑒于多方面原因,蘋果實際上推遲了ATS的強制執行,有興趣可以到蘋果官方了解)。

          題外話:關于短連接、長連接的定義,微信是一個特例,微信在網絡通信這一層做的比較徹底和極端,幾乎再造了一套針對移動端IM的網絡層框架(詳見:《如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源》),所以針對微信來說短連接可能并不能就是HTTP/HTTPS了。

          總之,無論是即時通訊IM還是其它應用,在移動網絡日益發達的今天,安全顯的尤為重要,HTTPS已經越來越普及,盡快擁抱它才是符合技術潮流的。

          本文將嘗試用通俗易懂的語言,一步步還原HTTPS的設計過程,以便您能輕松理解為什么HTTPS最終會是這副模樣。但鑒于HTTPS的復雜性,本文的文字主要是為了方便您的理解,而并不代表完全遵從HTTPS的真實設計過程。在閱讀本文時,你可以嘗試放下已有的對HTTPS的理解,這樣更利于您“理解”這個過程和技術原理。

          學習交流:

          - 即時通訊開發交流3群:185926912[推薦]

          - 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM

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

          2、關于作者

          翟志軍,個人博客地址:https://showme.codes/,Github:https://github.com/zacker330。感謝作者的原創分享。

          3、相關文章

          要理解HTTPS,須對HTTP協議有所了解,以下文章可能是您需要的:

          網絡編程懶人入門(七):深入淺出,全面理解HTTP協議

          從HTTP/0.9到HTTP/2:一文讀懂HTTP協議的歷史演變和設計思路

          腦殘式網絡編程入門(三):HTTP協議必知必會的一些知識

          現代移動端網絡短連接的優化手段總結:請求速度、弱網適應、安全保障

          IM開發基礎知識補課(四):正確理解HTTP短連接中的Cookie、Session和Token

          本文是IM通訊安全知識系列文章中的第7篇,此系列總目錄如下:

          即時通訊安全篇(一):正確地理解和使用Android端加密算法

          即時通訊安全篇(二):探討組合加密算法在IM中的應用

          即時通訊安全篇(三):常用加解密算法與通訊安全講解

          即時通訊安全篇(四):實例分析Android中密鑰硬編碼的風險

          即時通訊安全篇(五):對稱加密技術在Android平臺上的應用實踐

          即時通訊安全篇(六):非對稱加密技術的原理與應用實踐

          即時通訊安全篇(七):如果這樣來理解HTTPS原理,一篇就夠了》(本文)

          4、一個引子

          我們先不了聊HTTP/HTTPS,我們先從一個IM聊天軟件說起。

          假設我們想要實現A能發一個hello消息給B: 

          因為只是為了方便講解原理,我們要實現這個IM聊天的通信功能,本文只考慮安全性問題。

          那么我們的這個IM聊天功能,安全性上必須要達到:

          A發給B的hello消息包,即使被中間人攔截到了,也無法得知消息的內容。

          好,帶著這個問題,我來繼續往下理解基本的通信安全知識。

          好,問題域已經定義好了(現實中當然不止這一種定義)。對于解決方案,很容易就想到了對消息進行加密。

          題外話,但是只有這一種方法嗎?我看未必,說不定在將來會出現一種物質打破當前世界的通信假設,實現真正意義上的保密。

          對于A與B這樣的簡單通信模型,我們很容易做出選擇: 對稱加密算法

          這就是對稱加密算法,其中圖中的密鑰S同時扮演加密和解密的角色。具體細節不是本文范疇。

          如上圖所示,只要這個密鑰S不公開給第三者,同時密鑰S足夠安全,我們就解決了我們一開始所定問題域了。因為世界上有且只有A與B知道如何加密和解密他們之間的消息。

          但是,在WWW環境下,我們的Web服務器的通信模型沒有這么簡單:

          如果服務器端對所有的客戶端通信都使用同樣的對稱加密算法,無異于沒有加密。那怎么辦呢?即能使用對稱加密算法,又不公開密鑰?請讀者思考21秒鐘。^_^

          答案是:Web服務器與每個客戶端使用不同的對稱加密算法:

          5、如何確定對稱加密算法

          慢著,另一個問題來了,我們的服務器端怎么告訴客戶端該使用哪種對稱加密算法?

          當然是通過協商:

          但是,你協商的過程是沒有加密的,還是會被中間人攔截。那我們再對這個協商過程進行對稱加密就好了,那你對協商過程加密的加密還是沒有加密,怎么辦?再加密不就好了……好吧,進行雞生蛋蛋生雞的問題了。

          6、如何對協商過程進行加密

          新問題來了,如何對協商過程進行加密?密碼學領域中,有一種稱為“非對稱加密”的加密算法,特點是私鑰加密后的密文,只要是公鑰,都可以解密,但是公鑰加密后的密文,只有私鑰可以解密。私鑰只有一個人有,而公鑰可以發給所有的人。

          雖然服務器端向A、B……的方向還是不安全的,但是至少A、B向服務器端方向是安全的。

          好了,如何協商加密算法的問題,我們解決了:使用非對稱加密算法進行對稱加密算法協商過程。

          這下,你明白為什么HTTPS同時需要對稱加密算法和非對稱加密算法了吧?

          7、協商什么加密算法

          要達到Web服務器針對每個客戶端使用不同的對稱加密算法,同時,我們也不能讓第三者知道這個對稱加密算法是什么,怎么辦?

          使用隨機數,就是使用隨機數來生成對稱加密算法。這樣就可以做到服務器和客戶端每次交互都是新的加密算法、只有在交互的那一該才確定加密算法。

          這下,你明白為什么HTTPS協議握手階段會有這么多的隨機數了吧。

          8、如何得到公鑰?

          細心的人可能已經注意到了如果使用非對稱加密算法,我們的客戶端A,B需要一開始就持有公鑰,要不沒法開展加密行為啊。

          這下,我們又遇到新問題了,如何讓A、B客戶端安全地得到公鑰?

          我能想到的方案只有這些:

          方案1:服務器端將公鑰發送給每一個客戶端;

          方案2:服務器端將公鑰放到一個遠程服務器,客戶端可以請求得到。

          我們選擇方案1,因為方案2又多了一次請求,還要另外處理公鑰的放置問題。

          9、公鑰被調包了怎么辦?又是一個雞生蛋蛋生雞問題?

          但是方案1有個問題:如果服務器端發送公鑰給客戶端時,被中間人調包了,怎么辦?

          我畫了張圖方便理解:

          顯然,讓每個客戶端的每個瀏覽器默認保存所有網站的公鑰是不現實的。

          10、使用第三方機構的公鑰解決雞生蛋蛋生雞問題

          公鑰被調包的問題出現,是因為我們的客戶端無法分辨返回公鑰的人到底是中間人,還是真的服務器。這其實就是密碼學中提的身份驗證問題。

          如果讓你來解決,你怎么解決?如果你了解過HTTPS,會知道使用數字證書來解決。但是你想過證書的本質是什么么?請放下你對HTTPS已有的知識,自己嘗試找到解決方案。

          我是這樣解決的。既然服務器需要將公鑰傳給客戶端,這個過程本身是不安全,那么我們為什么不對這個過程本身再加密一次?可是,你是使用對稱加密,還是非對稱加密?這下好了,我感覺又進了雞生蛋蛋生雞問題了。

          問題的難點是如果我們選擇直接將公鑰傳遞給客戶端的方案,我們始終無法解決公鑰傳遞被中間人調包的問題。

          所以,我們不能直接將服務器的公鑰傳遞給客戶端,而是第三方機構使用它的私鑰對我們的公鑰進行加密后,再傳給客戶端。客戶端再使用第三方機構的公鑰進行解密。

          下圖就是我們設計的第一版“數字證書”,證書中只有服務器交給第三方機構的公鑰,而且這個公鑰被第三方機構的私鑰加密了:

          如果能解密,就說明這個公鑰沒有被中間人調包。因為如果中間人使用自己的私鑰加密后的東西傳給客戶端,客戶端是無法使用第三方的公鑰進行解密的。

          原理圖如下:

          話到此,我以為解決問題了。但是現實中HTTPS,還有一個數字簽名的概念,我沒法理解它的設計理由。

          原來,我漏掉了一個場景:

          第三方機構不可能只給你一家公司制作證書,它也可能會給中間人這樣有壞心思的公司發放證書。這樣的,中間人就有機會對你的證書進行調包,客戶端在這種情況下是無法分辨出是接收的是你的證書,還是中間人的。因為不論中間人,還是你的證書,都能使用第三方機構的公鑰進行解密。

          像下面這樣。。。

          第三方機構向多家公司頒發證書的情況: 

          客戶端能解密同一家第三機構頒發的所有證書: 

          最終導致其它持有同一家第三方機構證書的中間人可以進行調包:

          11、數字簽名,解決同一機構頒發的不同證書被篡改問題

          要解決這個問題,我們首先要想清楚一個問題,辨別同一機構下不同證書的這個職責,我們應該放在哪?

          只能放到客戶端了。意思是,客戶端在拿到證書后,自己就有能力分辨證書是否被篡改了。如何才能有這個能力呢?

          我們從現實中找靈感。比如你是HR,你手上拿到候選人的學歷證書,證書上寫了持證人,頒發機構,頒發時間等等,同時證書上,還寫有一個最重要的:證書編號!我們怎么鑒別這張證書是的真偽呢?只要拿著這個證書編號上相關機構去查,如果證書上的持證人與現實的這個候選人一致,同時證書編號也能對應上,那么就說明這個證書是真實的。

          我們的客戶端能不能采用這個機制呢?像這樣: 

          可是,這個“第三方機構”到底是在哪呢?是一個遠端服務?不可能吧?如果是個遠端服務,整個交互都會慢了。所以,這個第三方機構的驗證功能只能放在客戶端的本地了。

          12、客戶端本地怎么驗證證書呢?

          客戶端本地怎么驗證證書呢?答案是證書本身就已經告訴客戶端怎么驗證證書的真偽。

          也就是證書上寫著如何根據證書的內容生成證書編號。客戶端拿到證書后根據證書上的方法自己生成一個證書編號,如果生成的證書編號與證書上的證書編號相同,那么說明這個證書是真實的。

          同時,為避免證書編號本身又被調包,所以使用第三方的私鑰進行加密。

          這地方有些抽象,我們來個圖幫助理解:

          證書的制作如上圖所示。證書中的“編號生成方法MD5”就是告訴客戶端:你使用MD5對證書的內容求值就可以得到一個證書編號。

          當客戶端拿到證書后,開始對證書中的內容進行驗證,如果客戶端計算出來的證書編號與證書中的證書編號相同,則驗證通過:

          但是第三方機構的公鑰怎么跑到了客戶端的機器中呢?世界上這么多機器。

          其實呢,現實中,瀏覽器和操作系統都會維護一個權威的第三方機構列表(包括它們的公鑰)。因為客戶端接收到的證書中會寫有頒發機構,客戶端就根據這個頒發機構的值在本地找相應的公鑰。

          題外話:

          如果瀏覽器和操作系統這道防線被破了,就沒辦法。想想當年自己裝過的非常規XP系統,都害怕。

          說到這里,想必大家已經知道上文所說的,證書就是HTTPS中數字證書,證書編號就是數字簽名,而第三方機構就是指數字證書簽發機構(CA)。

          13、CA如何頒發數字證書給服務器端的?

          當我聽到這個問題時,我誤以為,我們的SERVER需要發網絡請求到CA部門的服務器來拿這個證書。?? 到底是我理解能力問題,還是。。

          其實,問題應該是CA如何頒發給我們的網站管理員,而我們的管理員又如何將這個數字證書放到我們的服務器上。

          我們如何向CA申請呢?每個CA機構都大同小異,我在網上找了一個: 

          拿到證書后,我們就可以將證書配置到自己的服務器上了。那么如何配置?這是具體細節了,留給大家google了。

          14、也許我們需要整理一下思路

          我們通過推算的方式嘗試還原HTTPS的設計過程。這樣,我們也就明白了為什么HTTPS比HTTP多那么多次的交互,為什么HTTPS的性能會差,以及找到HTTPS的性能優化點。

          而上面一大堆工作都是為了讓客戶端與服務器端安全地協商出一個對稱加密算法。這就是HTTPS中的SSL/TLS協議主要干的活。剩下的就是通信時雙方使用這個對稱加密算法進行加密解密。

          以下是一張HTTPS協議的真實交互圖(從網上copy的,忘了從哪了,如果侵權麻煩告知):

          15、能不能用一句話總結HTTPS?

          答案是不能,因為HTTPS本身實在太復雜。

          但是我還是嘗試使用一段話來總結HTTPS:

          HTTPS要使客戶端與服務器端的通信過程得到安全保證,必須使用的對稱加密算法,但是協商對稱加密算法的過程,需要使用非對稱加密算法來保證安全,然而直接使用非對稱加密的過程本身也不安全,會有中間人篡改公鑰的可能性,所以客戶端與服務器不直接使用公鑰,而是使用數字證書簽發機構頒發的證書來保證非對稱加密過程本身的安全。這樣通過這些機制協商出一個對稱加密算法,就此雙方使用該算法進行加密解密。從而解決了客戶端與服務器端之間的通信安全問題。

          好長的一段話。

          16、后記

          以上是個人為理解HTTPS而編造出來的自圓其說的看法。頂多只能算是HTTPS的科普文章。如有錯誤,請指出,萬分感謝。

          那么,我為什么會覺得以這種方式理解HTTPS會更容易呢?我個人給出的答案是:當你自己為一家人做一次菜時,你就會理解媽媽天天做菜的不易了。

          17、參考資料

          HTTPS為什么安全 &分析 HTTPS 連接建立全過程

          數字證書的基礎知識

          理解 HTTPS

          HTTPS 是如何保證安全的?

          圖解SSL/TLS協議

          The First Few Milliseconds of an HTTPS Connection

          SSL/TLS原理詳解

          附錄:更多通信安全方面的文章

          傳輸層安全協議SSL/TLS的Java平臺實現簡介和Demo演示

          理論聯系實際:一套典型的IM通信協議設計詳解(含安全層設計)

          微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解

          來自阿里OpenIM:打造安全可靠即時通訊服務的技術實踐分享

          簡述實時音視頻聊天中端到端加密(E2EE)的工作原理

          移動端安全通信的利器——端到端加密(E2EE)技術詳解

          Web端即時通訊安全:跨站點WebSocket劫持漏洞詳解(含示例代碼)

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

          IM開發基礎知識補課(四):正確理解HTTP短連接中的Cookie、Session和Token

          快速讀懂量子通信、量子加密技術

          即時通訊安全篇(七):如果這樣來理解HTTPS原理,一篇就夠了

          >> 更多同類文章 ……

          (本文同步發布于:http://www.52im.net/thread-1890-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
          主站蜘蛛池模板: 齐齐哈尔市| 隆昌县| 珠海市| 抚宁县| 桐乡市| 广元市| 讷河市| 彰化市| 东山县| 东丽区| 浦北县| 永德县| 洛川县| 博客| 紫阳县| 北川| 宾川县| 庆阳市| 葵青区| 玉门市| 永兴县| 六安市| 绵竹市| 友谊县| 南皮县| 辰溪县| 正镶白旗| 二连浩特市| 马尔康县| 新密市| 赣榆县| 江口县| 平阳县| 阳江市| 黄骅市| 化德县| 邳州市| 金乡县| 庆云县| 京山县| 进贤县|