大家好,我是藍胖子,在之前# MYSQL 是如何保證binlog 和redo log同時提交的?這篇文章裡,我們可以從mysql的設計中學會如何讓兩個服務的呼叫邏輯達到最終一致性,這也是分散式事務實現方式之一。今天來看看我們能夠從httpsd設計中得到哪些啟發可以用於業務系統開發中。
https原理分析
首先,我們來看下https 涉及到的握手流程,在http的三次握手基礎上,https還要進行tls的握手協議。在經過tls握手後,後續客戶端和服務端傳送的訊息也就都是加密的了。我們著重要看的就是tls握手過程。tls協議目前主要現存兩個版本,我們都來看看。
tls1.2
首先,來看下tls1.2 協議下的握手流程。
在瞭解程式邏輯究竟為何如此設計之前,要搞懂我們這樣做的目的。https之所以要用tls,無非就是為了兩個目的,
- 第一個目的: 讓客戶端能夠認證服務端的身份資訊,防止訪問不安全的釣魚網站。
- 第二個目的: 對伺服器和客戶端之間的訊息進行加密,不再明文傳輸。
對於第一個目的,可以透過數字證書解決,CA 向伺服器頒發一個證書,在一次tls握手中,伺服器會向客戶端發放自己的證書,客戶端在得到證書後向CA驗證證書的合法性,如果合法,說明服務端是經過認證的,可以信任。
驗證的原理則是透過公私鑰加密演算法和摘要演算法
,CA有自己的私鑰,同時CA會將自己的公鑰公佈出去,然後CA對伺服器的證書內容進行摘要計算,再對摘要進行私鑰加密,私鑰加密的內容只有公鑰才能解密,私鑰加密的內容稱為簽名資訊,這段簽名資訊同樣也會包含在證書中。
客戶端在得到服務端證書的時候,透過對簽名資訊進行解密,得到證書的摘要資訊,這個時候再對證書的內容進行摘要計算,看計算結果是否和解密得到的摘要資訊一致,如果證書內容沒被篡改的話,相同摘要演算法得到的摘要資訊應該是一致。
對於第二個目的,則是可以透過加密演算法,為了效能,會話加密將會採用對稱加密演算法,這裡的關鍵是得到一個會話金鑰,但是為了安全性,會話金鑰又不能直接採用明文進行傳輸。
所以tls是這樣做的,客戶端首先會生成一個隨機數A,並已明文傳遞給服務端,服務端也會生成一個隨機數B,並且把它傳遞給客戶端,同時還會把數字證書傳給客戶端。數字證書中包含了服務端的公鑰資訊,客戶端在收到證書取出其中公鑰後,會再次生成一個隨機數,隨機數被稱作pre master key
,這個隨機數會透過證書中的公鑰進行加密,傳遞給服務端,服務端會用自己的私鑰對其進行解密,因為公鑰加密的資訊只能私鑰才能解密,所以在服務端私鑰不會洩露的情況下,駭客即使截獲了報文,依然不能知道pre master key
的值。
接著,便是服務端和客戶端用相同的計算金鑰的演算法,以客戶端和服務端的隨機數A,B和pre master key生成相同的會話金鑰,用於後續的通訊進行對稱加密。整個過程如下圖所示,可以看到金鑰的產生過程經歷兩次RTT,才會開始進行後續的請求傳送。
請求一來一回稱為一次RTT
關於tls1.2的完整握手過程,我也總結一個流程圖,方便大家參考,
tls1.3
在瞭解了tls1.2的握手過程後,我們來看看tls1.3在握手過程中有哪些最佳化。tls1.3 廢棄了一些金鑰交換演算法如RSA,預設用橢圓曲線ECDHE金鑰交換演算法,將金鑰的產生時間從兩次RTT縮短至了一次RTT。
廢棄RSA金鑰交換演算法的另一個原因在於,使用RSA金鑰交換演算法,如果駭客持續截獲https報文,如果數字證書中的公鑰對應的服務端私鑰洩露,那麼駭客便可以將之前的歷史報文進行解密,RSA金鑰交換演算法不具有
前向安全
性。前向安全指的是長期使用的主金鑰洩漏不會導致過去的會話金鑰洩漏
如下圖所示,客戶端和服務端都各自生成自己的一對用於ECDHE計算的隨機公私鑰和各自的隨機數, 然後將各自的公鑰和隨機數傳給對方,之後便可以各自透過這些資訊計算出相同的會話金鑰。
ECDHE 金鑰交換具有前向安全性,因為參與會話金鑰計算的私鑰每次都是隨機生成的,這樣即使駭客獲得了當前的私鑰,也不能對歷史https報文進行解密。
可以看到,ECDHE金鑰交換演算法只交換了各自的公鑰便可以計算出會話金鑰,即使駭客截獲了訊息內容,但是隻有公鑰,沒有私鑰也不能計算出會話金鑰。我將tls1.3的握手過程總結到了下面的流程圖中,大家可以參考下,
im訊息加密解決方案
以上是https訊息加密的實現原理,如果我們也想在訊息傳輸中進行加密和認證處理,比如在im系統中對im訊息加密,那麼完全可以參考https的實現原理。
我們需要為im系統做訊息加密
和訊息防篡改
的設計。
對於訊息加密,參考https的互動,可以採用對稱加密對後續會話內容進行對稱加密,比如AES演算法,加密的金鑰可以採用ECDHE金鑰交換演算法,具有前向安全性。
對於訊息防篡改,可以採用訊息摘要演算法,常見的摘要演算法有md5,sha256,透過對加密後的報文進行摘要計算,在獲取到報文的第一時間就透過對比計算出的訊息摘要和報文中的訊息摘要 來判斷報文是否經過篡改。
更進一步,還可以設計一組只有im客戶端和服務端知道的金鑰,讓客戶端在進行摘要計算時,加上金鑰,也就是透過類似hmac的訊息認證演算法,進行摘要計算,這樣在對端接收到報文後,正常情況下,透過相同的訊息認證演算法和金鑰會得到相同的摘要結果,如果計算的摘要結果和報文中的摘要結果不一致,那麼說明報文不是從信任的客戶端發來的,直接拒絕,這樣便達到了訊息認證
的目的。
📢📢注意,在im訊息系統設計時,對於訊息認證我們沒有去生成一個數字證書,對於https,客戶端對服務端的訊息認證卻是透過數字證書的認證完成的。
這是因為在通訊前,客戶端和服務端對於彼此是未知的,它們只能透過一個已知的第三方機構CA完成這樣的認證。
而我們自己寫的程式就不一樣,可以設計一個金鑰讓im客戶端和im服務端程式都使用這個金鑰對報文進行hmac訊息認證,因為金鑰只有自己的程式知道,如果得到的認證碼和計算出的不一致,那麼訊息必然來自第三方。