1、前言
可能有初學(xué)者會(huì)問(wèn),即時(shí)通訊應(yīng)用的通信安全,不就是對(duì)Socket長(zhǎng)連接進(jìn)行SSL/TLS加密這些知識(shí)嗎,干嗎要理解HTTPS協(xié)議呢。
這其實(shí)是個(gè)誤解:當(dāng)今主流的移動(dòng)端IM數(shù)據(jù)通信,總結(jié)下來(lái)無(wú)外乎就是長(zhǎng)連接+短連接的方式,長(zhǎng)連接就是眾所周之的TCP、UDP、WebSocket(WebSocket的本質(zhì)還是TCP),而短連接就是HTTP/HTTPS了。即時(shí)通訊IM應(yīng)用中,短連接的安全跟長(zhǎng)連接相比,同樣很重要。市面上的主流短連接通信方式,都已逐步從HTTP過(guò)渡到HTTPS了(iOS上的應(yīng)用就更徹底了,蘋(píng)果直接強(qiáng)制要求使用HTTPS協(xié)議,否則不允許上架APP Store,詳見(jiàn)《蘋(píng)果即將強(qiáng)制實(shí)施 ATS,你的APP準(zhǔn)備好切換到HTTPS了嗎?》。不過(guò),鑒于多方面原因,蘋(píng)果實(shí)際上推遲了ATS的強(qiáng)制執(zhí)行,有興趣可以到蘋(píng)果官方了解)。
題外話:關(guān)于短連接、長(zhǎng)連接的定義,微信是一個(gè)特例,微信在網(wǎng)絡(luò)通信這一層做的比較徹底和極端,幾乎再造了一套針對(duì)移動(dòng)端IM的網(wǎng)絡(luò)層框架(詳見(jiàn):《如約而至:微信自用的移動(dòng)端IM網(wǎng)絡(luò)層跨平臺(tái)組件庫(kù)Mars已正式開(kāi)源》),所以針對(duì)微信來(lái)說(shuō)短連接可能并不能就是HTTP/HTTPS了。
總之,無(wú)論是即時(shí)通訊IM還是其它應(yīng)用,在移動(dòng)網(wǎng)絡(luò)日益發(fā)達(dá)的今天,安全顯的尤為重要,HTTPS已經(jīng)越來(lái)越普及,盡快擁抱它才是符合技術(shù)潮流的。
本文將嘗試用通俗易懂的語(yǔ)言,一步步還原HTTPS的設(shè)計(jì)過(guò)程,以便您能輕松理解為什么HTTPS最終會(huì)是這副模樣。但鑒于HTTPS的復(fù)雜性,本文的文字主要是為了方便您的理解,而并不代表完全遵從HTTPS的真實(shí)設(shè)計(jì)過(guò)程。在閱讀本文時(shí),你可以嘗試放下已有的對(duì)HTTPS的理解,這樣更利于您“理解”這個(gè)過(guò)程和技術(shù)原理。
學(xué)習(xí)交流:
- 即時(shí)通訊開(kāi)發(fā)交流3群:185926912[推薦]
- 移動(dòng)端IM開(kāi)發(fā)入門(mén)文章:《新手入門(mén)一篇就夠:從零開(kāi)發(fā)移動(dòng)端IM》
(本文同步發(fā)布于:http://www.52im.net/thread-1890-1-1.html)
2、關(guān)于作者
翟志軍,個(gè)人博客地址:https://showme.codes/,Github:https://github.com/zacker330。感謝作者的原創(chuàng)分享。
3、相關(guān)文章
要理解HTTPS,須對(duì)HTTP協(xié)議有所了解,以下文章可能是您需要的:
《網(wǎng)絡(luò)編程懶人入門(mén)(七):深入淺出,全面理解HTTP協(xié)議》
《從HTTP/0.9到HTTP/2:一文讀懂HTTP協(xié)議的歷史演變和設(shè)計(jì)思路》
《腦殘式網(wǎng)絡(luò)編程入門(mén)(三):HTTP協(xié)議必知必會(huì)的一些知識(shí)》
《現(xiàn)代移動(dòng)端網(wǎng)絡(luò)短連接的優(yōu)化手段總結(jié):請(qǐng)求速度、弱網(wǎng)適應(yīng)、安全保障》
《IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(四):正確理解HTTP短連接中的Cookie、Session和Token》
本文是IM通訊安全知識(shí)系列文章中的第7篇,此系列總目錄如下:
《即時(shí)通訊安全篇(一):正確地理解和使用Android端加密算法》
《即時(shí)通訊安全篇(二):探討組合加密算法在IM中的應(yīng)用》
《即時(shí)通訊安全篇(三):常用加解密算法與通訊安全講解》
《即時(shí)通訊安全篇(四):實(shí)例分析Android中密鑰硬編碼的風(fēng)險(xiǎn)》
《即時(shí)通訊安全篇(五):對(duì)稱(chēng)加密技術(shù)在Android平臺(tái)上的應(yīng)用實(shí)踐》
《即時(shí)通訊安全篇(六):非對(duì)稱(chēng)加密技術(shù)的原理與應(yīng)用實(shí)踐》
4、一個(gè)引子
我們先不了聊HTTP/HTTPS,我們先從一個(gè)IM聊天軟件說(shuō)起。
假設(shè)我們想要實(shí)現(xiàn)A能發(fā)一個(gè)hello消息給B:
因?yàn)橹皇菫榱朔奖阒v解原理,我們要實(shí)現(xiàn)這個(gè)IM聊天的通信功能,本文只考慮安全性問(wèn)題。
那么我們的這個(gè)IM聊天功能,安全性上必須要達(dá)到:
A發(fā)給B的hello消息包,即使被中間人攔截到了,也無(wú)法得知消息的內(nèi)容。
好,帶著這個(gè)問(wèn)題,我來(lái)繼續(xù)往下理解基本的通信安全知識(shí)。
好,問(wèn)題域已經(jīng)定義好了(現(xiàn)實(shí)中當(dāng)然不止這一種定義)。對(duì)于解決方案,很容易就想到了對(duì)消息進(jìn)行加密。
題外話,但是只有這一種方法嗎?我看未必,說(shuō)不定在將來(lái)會(huì)出現(xiàn)一種物質(zhì)打破當(dāng)前世界的通信假設(shè),實(shí)現(xiàn)真正意義上的保密。
對(duì)于A與B這樣的簡(jiǎn)單通信模型,我們很容易做出選擇: 對(duì)稱(chēng)加密算法
這就是對(duì)稱(chēng)加密算法,其中圖中的密鑰S同時(shí)扮演加密和解密的角色。具體細(xì)節(jié)不是本文范疇。
如上圖所示,只要這個(gè)密鑰S不公開(kāi)給第三者,同時(shí)密鑰S足夠安全,我們就解決了我們一開(kāi)始所定問(wèn)題域了。因?yàn)槭澜缟嫌星抑挥蠥與B知道如何加密和解密他們之間的消息。
但是,在WWW環(huán)境下,我們的Web服務(wù)器的通信模型沒(méi)有這么簡(jiǎn)單:
如果服務(wù)器端對(duì)所有的客戶(hù)端通信都使用同樣的對(duì)稱(chēng)加密算法,無(wú)異于沒(méi)有加密。那怎么辦呢?即能使用對(duì)稱(chēng)加密算法,又不公開(kāi)密鑰?請(qǐng)讀者思考21秒鐘。^_^
答案是:Web服務(wù)器與每個(gè)客戶(hù)端使用不同的對(duì)稱(chēng)加密算法:
5、如何確定對(duì)稱(chēng)加密算法
慢著,另一個(gè)問(wèn)題來(lái)了,我們的服務(wù)器端怎么告訴客戶(hù)端該使用哪種對(duì)稱(chēng)加密算法?
當(dāng)然是通過(guò)協(xié)商:
但是,你協(xié)商的過(guò)程是沒(méi)有加密的,還是會(huì)被中間人攔截。那我們?cè)賹?duì)這個(gè)協(xié)商過(guò)程進(jìn)行對(duì)稱(chēng)加密就好了,那你對(duì)協(xié)商過(guò)程加密的加密還是沒(méi)有加密,怎么辦?再加密不就好了……好吧,進(jìn)行雞生蛋蛋生雞的問(wèn)題了。
6、如何對(duì)協(xié)商過(guò)程進(jìn)行加密
新問(wèn)題來(lái)了,如何對(duì)協(xié)商過(guò)程進(jìn)行加密?密碼學(xué)領(lǐng)域中,有一種稱(chēng)為“非對(duì)稱(chēng)加密”的加密算法,特點(diǎn)是私鑰加密后的密文,只要是公鑰,都可以解密,但是公鑰加密后的密文,只有私鑰可以解密。私鑰只有一個(gè)人有,而公鑰可以發(fā)給所有的人。
雖然服務(wù)器端向A、B……的方向還是不安全的,但是至少A、B向服務(wù)器端方向是安全的。
好了,如何協(xié)商加密算法的問(wèn)題,我們解決了:使用非對(duì)稱(chēng)加密算法進(jìn)行對(duì)稱(chēng)加密算法協(xié)商過(guò)程。
這下,你明白為什么HTTPS同時(shí)需要對(duì)稱(chēng)加密算法和非對(duì)稱(chēng)加密算法了吧?
7、協(xié)商什么加密算法
要達(dá)到Web服務(wù)器針對(duì)每個(gè)客戶(hù)端使用不同的對(duì)稱(chēng)加密算法,同時(shí),我們也不能讓第三者知道這個(gè)對(duì)稱(chēng)加密算法是什么,怎么辦?
使用隨機(jī)數(shù),就是使用隨機(jī)數(shù)來(lái)生成對(duì)稱(chēng)加密算法。這樣就可以做到服務(wù)器和客戶(hù)端每次交互都是新的加密算法、只有在交互的那一該才確定加密算法。
這下,你明白為什么HTTPS協(xié)議握手階段會(huì)有這么多的隨機(jī)數(shù)了吧。
8、如何得到公鑰?
細(xì)心的人可能已經(jīng)注意到了如果使用非對(duì)稱(chēng)加密算法,我們的客戶(hù)端A,B需要一開(kāi)始就持有公鑰,要不沒(méi)法開(kāi)展加密行為啊。
這下,我們又遇到新問(wèn)題了,如何讓A、B客戶(hù)端安全地得到公鑰?
我能想到的方案只有這些:
方案1:服務(wù)器端將公鑰發(fā)送給每一個(gè)客戶(hù)端;
方案2:服務(wù)器端將公鑰放到一個(gè)遠(yuǎn)程服務(wù)器,客戶(hù)端可以請(qǐng)求得到。
我們選擇方案1,因?yàn)榉桨?又多了一次請(qǐng)求,還要另外處理公鑰的放置問(wèn)題。
9、公鑰被調(diào)包了怎么辦?又是一個(gè)雞生蛋蛋生雞問(wèn)題?
但是方案1有個(gè)問(wèn)題:如果服務(wù)器端發(fā)送公鑰給客戶(hù)端時(shí),被中間人調(diào)包了,怎么辦?
我畫(huà)了張圖方便理解:
顯然,讓每個(gè)客戶(hù)端的每個(gè)瀏覽器默認(rèn)保存所有網(wǎng)站的公鑰是不現(xiàn)實(shí)的。
10、使用第三方機(jī)構(gòu)的公鑰解決雞生蛋蛋生雞問(wèn)題
公鑰被調(diào)包的問(wèn)題出現(xiàn),是因?yàn)槲覀兊目蛻?hù)端無(wú)法分辨返回公鑰的人到底是中間人,還是真的服務(wù)器。這其實(shí)就是密碼學(xué)中提的身份驗(yàn)證問(wèn)題。
如果讓你來(lái)解決,你怎么解決?如果你了解過(guò)HTTPS,會(huì)知道使用數(shù)字證書(shū)來(lái)解決。但是你想過(guò)證書(shū)的本質(zhì)是什么么?請(qǐng)放下你對(duì)HTTPS已有的知識(shí),自己嘗試找到解決方案。
我是這樣解決的。既然服務(wù)器需要將公鑰傳給客戶(hù)端,這個(gè)過(guò)程本身是不安全,那么我們?yōu)槭裁床粚?duì)這個(gè)過(guò)程本身再加密一次?可是,你是使用對(duì)稱(chēng)加密,還是非對(duì)稱(chēng)加密?這下好了,我感覺(jué)又進(jìn)了雞生蛋蛋生雞問(wèn)題了。
問(wèn)題的難點(diǎn)是如果我們選擇直接將公鑰傳遞給客戶(hù)端的方案,我們始終無(wú)法解決公鑰傳遞被中間人調(diào)包的問(wèn)題。
所以,我們不能直接將服務(wù)器的公鑰傳遞給客戶(hù)端,而是第三方機(jī)構(gòu)使用它的私鑰對(duì)我們的公鑰進(jìn)行加密后,再傳給客戶(hù)端??蛻?hù)端再使用第三方機(jī)構(gòu)的公鑰進(jìn)行解密。
下圖就是我們?cè)O(shè)計(jì)的第一版“數(shù)字證書(shū)”,證書(shū)中只有服務(wù)器交給第三方機(jī)構(gòu)的公鑰,而且這個(gè)公鑰被第三方機(jī)構(gòu)的私鑰加密了:
如果能解密,就說(shuō)明這個(gè)公鑰沒(méi)有被中間人調(diào)包。因?yàn)槿绻虚g人使用自己的私鑰加密后的東西傳給客戶(hù)端,客戶(hù)端是無(wú)法使用第三方的公鑰進(jìn)行解密的。
原理圖如下:
話到此,我以為解決問(wèn)題了。但是現(xiàn)實(shí)中HTTPS,還有一個(gè)數(shù)字簽名的概念,我沒(méi)法理解它的設(shè)計(jì)理由。
原來(lái),我漏掉了一個(gè)場(chǎng)景:
第三方機(jī)構(gòu)不可能只給你一家公司制作證書(shū),它也可能會(huì)給中間人這樣有壞心思的公司發(fā)放證書(shū)。這樣的,中間人就有機(jī)會(huì)對(duì)你的證書(shū)進(jìn)行調(diào)包,客戶(hù)端在這種情況下是無(wú)法分辨出是接收的是你的證書(shū),還是中間人的。因?yàn)椴徽撝虚g人,還是你的證書(shū),都能使用第三方機(jī)構(gòu)的公鑰進(jìn)行解密。
像下面這樣。。。
第三方機(jī)構(gòu)向多家公司頒發(fā)證書(shū)的情況:
客戶(hù)端能解密同一家第三機(jī)構(gòu)頒發(fā)的所有證書(shū):
最終導(dǎo)致其它持有同一家第三方機(jī)構(gòu)證書(shū)的中間人可以進(jìn)行調(diào)包:
11、數(shù)字簽名,解決同一機(jī)構(gòu)頒發(fā)的不同證書(shū)被篡改問(wèn)題
要解決這個(gè)問(wèn)題,我們首先要想清楚一個(gè)問(wèn)題,辨別同一機(jī)構(gòu)下不同證書(shū)的這個(gè)職責(zé),我們應(yīng)該放在哪?
只能放到客戶(hù)端了。意思是,客戶(hù)端在拿到證書(shū)后,自己就有能力分辨證書(shū)是否被篡改了。如何才能有這個(gè)能力呢?
我們從現(xiàn)實(shí)中找靈感。比如你是HR,你手上拿到候選人的學(xué)歷證書(shū),證書(shū)上寫(xiě)了持證人,頒發(fā)機(jī)構(gòu),頒發(fā)時(shí)間等等,同時(shí)證書(shū)上,還寫(xiě)有一個(gè)最重要的:證書(shū)編號(hào)!我們?cè)趺磋b別這張證書(shū)是的真?zhèn)文兀恐灰弥@個(gè)證書(shū)編號(hào)上相關(guān)機(jī)構(gòu)去查,如果證書(shū)上的持證人與現(xiàn)實(shí)的這個(gè)候選人一致,同時(shí)證書(shū)編號(hào)也能對(duì)應(yīng)上,那么就說(shuō)明這個(gè)證書(shū)是真實(shí)的。
我們的客戶(hù)端能不能采用這個(gè)機(jī)制呢?像這樣:
可是,這個(gè)“第三方機(jī)構(gòu)”到底是在哪呢?是一個(gè)遠(yuǎn)端服務(wù)?不可能吧?如果是個(gè)遠(yuǎn)端服務(wù),整個(gè)交互都會(huì)慢了。所以,這個(gè)第三方機(jī)構(gòu)的驗(yàn)證功能只能放在客戶(hù)端的本地了。
12、客戶(hù)端本地怎么驗(yàn)證證書(shū)呢?
客戶(hù)端本地怎么驗(yàn)證證書(shū)呢?答案是證書(shū)本身就已經(jīng)告訴客戶(hù)端怎么驗(yàn)證證書(shū)的真?zhèn)巍?/p>
也就是證書(shū)上寫(xiě)著如何根據(jù)證書(shū)的內(nèi)容生成證書(shū)編號(hào)??蛻?hù)端拿到證書(shū)后根據(jù)證書(shū)上的方法自己生成一個(gè)證書(shū)編號(hào),如果生成的證書(shū)編號(hào)與證書(shū)上的證書(shū)編號(hào)相同,那么說(shuō)明這個(gè)證書(shū)是真實(shí)的。
同時(shí),為避免證書(shū)編號(hào)本身又被調(diào)包,所以使用第三方的私鑰進(jìn)行加密。
這地方有些抽象,我們來(lái)個(gè)圖幫助理解:
證書(shū)的制作如上圖所示。證書(shū)中的“編號(hào)生成方法MD5”就是告訴客戶(hù)端:你使用MD5對(duì)證書(shū)的內(nèi)容求值就可以得到一個(gè)證書(shū)編號(hào)。
當(dāng)客戶(hù)端拿到證書(shū)后,開(kāi)始對(duì)證書(shū)中的內(nèi)容進(jìn)行驗(yàn)證,如果客戶(hù)端計(jì)算出來(lái)的證書(shū)編號(hào)與證書(shū)中的證書(shū)編號(hào)相同,則驗(yàn)證通過(guò):
但是第三方機(jī)構(gòu)的公鑰怎么跑到了客戶(hù)端的機(jī)器中呢?世界上這么多機(jī)器。
其實(shí)呢,現(xiàn)實(shí)中,瀏覽器和操作系統(tǒng)都會(huì)維護(hù)一個(gè)權(quán)威的第三方機(jī)構(gòu)列表(包括它們的公鑰)。因?yàn)榭蛻?hù)端接收到的證書(shū)中會(huì)寫(xiě)有頒發(fā)機(jī)構(gòu),客戶(hù)端就根據(jù)這個(gè)頒發(fā)機(jī)構(gòu)的值在本地找相應(yīng)的公鑰。
題外話:
如果瀏覽器和操作系統(tǒng)這道防線被破了,就沒(méi)辦法。想想當(dāng)年自己裝過(guò)的非常規(guī)XP系統(tǒng),都害怕。
說(shuō)到這里,想必大家已經(jīng)知道上文所說(shuō)的,證書(shū)就是HTTPS中數(shù)字證書(shū),證書(shū)編號(hào)就是數(shù)字簽名,而第三方機(jī)構(gòu)就是指數(shù)字證書(shū)簽發(fā)機(jī)構(gòu)(CA)。
13、CA如何頒發(fā)數(shù)字證書(shū)給服務(wù)器端的?
當(dāng)我聽(tīng)到這個(gè)問(wèn)題時(shí),我誤以為,我們的SERVER需要發(fā)網(wǎng)絡(luò)請(qǐng)求到CA部門(mén)的服務(wù)器來(lái)拿這個(gè)證書(shū)。?? 到底是我理解能力問(wèn)題,還是。。
其實(shí),問(wèn)題應(yīng)該是CA如何頒發(fā)給我們的網(wǎng)站管理員,而我們的管理員又如何將這個(gè)數(shù)字證書(shū)放到我們的服務(wù)器上。
我們?nèi)绾蜗駽A申請(qǐng)呢?每個(gè)CA機(jī)構(gòu)都大同小異,我在網(wǎng)上找了一個(gè):
拿到證書(shū)后,我們就可以將證書(shū)配置到自己的服務(wù)器上了。那么如何配置?這是具體細(xì)節(jié)了,留給大家google了。
14、也許我們需要整理一下思路
我們通過(guò)推算的方式嘗試還原HTTPS的設(shè)計(jì)過(guò)程。這樣,我們也就明白了為什么HTTPS比HTTP多那么多次的交互,為什么HTTPS的性能會(huì)差,以及找到HTTPS的性能優(yōu)化點(diǎn)。
而上面一大堆工作都是為了讓客戶(hù)端與服務(wù)器端安全地協(xié)商出一個(gè)對(duì)稱(chēng)加密算法。這就是HTTPS中的SSL/TLS協(xié)議主要干的活。剩下的就是通信時(shí)雙方使用這個(gè)對(duì)稱(chēng)加密算法進(jìn)行加密解密。
以下是一張HTTPS協(xié)議的真實(shí)交互圖(從網(wǎng)上copy的,忘了從哪了,如果侵權(quán)麻煩告知):
15、能不能用一句話總結(jié)HTTPS?
答案是不能,因?yàn)镠TTPS本身實(shí)在太復(fù)雜。
但是我還是嘗試使用一段話來(lái)總結(jié)HTTPS:
HTTPS要使客戶(hù)端與服務(wù)器端的通信過(guò)程得到安全保證,必須使用的對(duì)稱(chēng)加密算法,但是協(xié)商對(duì)稱(chēng)加密算法的過(guò)程,需要使用非對(duì)稱(chēng)加密算法來(lái)保證安全,然而直接使用非對(duì)稱(chēng)加密的過(guò)程本身也不安全,會(huì)有中間人篡改公鑰的可能性,所以客戶(hù)端與服務(wù)器不直接使用公鑰,而是使用數(shù)字證書(shū)簽發(fā)機(jī)構(gòu)頒發(fā)的證書(shū)來(lái)保證非對(duì)稱(chēng)加密過(guò)程本身的安全。這樣通過(guò)這些機(jī)制協(xié)商出一個(gè)對(duì)稱(chēng)加密算法,就此雙方使用該算法進(jìn)行加密解密。從而解決了客戶(hù)端與服務(wù)器端之間的通信安全問(wèn)題。
好長(zhǎng)的一段話。
16、后記
以上是個(gè)人為理解HTTPS而編造出來(lái)的自圓其說(shuō)的看法。頂多只能算是HTTPS的科普文章。如有錯(cuò)誤,請(qǐng)指出,萬(wàn)分感謝。
那么,我為什么會(huì)覺(jué)得以這種方式理解HTTPS會(huì)更容易呢?我個(gè)人給出的答案是:當(dāng)你自己為一家人做一次菜時(shí),你就會(huì)理解媽媽天天做菜的不易了。
17、參考資料
《HTTPS為什么安全 &分析 HTTPS 連接建立全過(guò)程》
《數(shù)字證書(shū)的基礎(chǔ)知識(shí)》
《理解 HTTPS》
附錄:更多通信安全方面的文章
《傳輸層安全協(xié)議SSL/TLS的Java平臺(tái)實(shí)現(xiàn)簡(jiǎn)介和Demo演示》
《理論聯(lián)系實(shí)際:一套典型的IM通信協(xié)議設(shè)計(jì)詳解(含安全層設(shè)計(jì))》
《微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解》
《來(lái)自阿里OpenIM:打造安全可靠即時(shí)通訊服務(wù)的技術(shù)實(shí)踐分享》
《簡(jiǎn)述實(shí)時(shí)音視頻聊天中端到端加密(E2EE)的工作原理》
《移動(dòng)端安全通信的利器——端到端加密(E2EE)技術(shù)詳解》
《Web端即時(shí)通訊安全:跨站點(diǎn)WebSocket劫持漏洞詳解(含示例代碼)》
《IM開(kāi)發(fā)基礎(chǔ)知識(shí)補(bǔ)課(四):正確理解HTTP短連接中的Cookie、Session和Token》
(本文同步發(fā)布于:http://www.52im.net/thread-1890-1-1.html)
作者:Jack Jiang (點(diǎn)擊作者姓名進(jìn)入Github)
出處:http://www.52im.net/space-uid-1.html
交流:歡迎加入即時(shí)通訊開(kāi)發(fā)交流群 215891622
討論:http://www.52im.net/
Jack Jiang同時(shí)是【原創(chuàng)Java
Swing外觀工程BeautyEye】和【輕量級(jí)移動(dòng)端即時(shí)通訊框架MobileIMSDK】的作者,可前往下載交流。
本博文
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處(也可前往 我的52im.net 找到我)。