在基於TCP長連接的CS鏈路中,如何保證數據流的安全性是開發者最關注的問題之一。本文深入淺出的給大家介紹一下在TCP連接中,使用RSA協商加密的方式,建立一個安全加密的通信鏈路,保證數據傳輸的安全性。文章分為3個主要部分,即RSA算法簡介,安全信道協商流程詳解和一些工程優化方法。期望大家在讀了我這篇文章之后能夠透徹的理解基於RSA協商加密方式的信道建立方式並能夠運用在自己的業務實踐中。
RSA算法簡介
加密算法是計算機通信安全的基石,加密算法分為2個大類,即”對稱加密算法“和”非對稱加密算法“。”對稱加密算法“的缺點比較明顯,即甲方必須把加密規則告訴乙方,否則無法解密。因此保存和傳遞密鑰,就成了最頭疼的問題。本文所依賴的加密算法RSA算法是一種”非對稱加密算法“,其具有以下特點:
- 乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
- 甲方獲取乙方的公鑰,然后用它對信息加密。
- 乙方得到加密后的信息,用私鑰解密。
其實關鍵知識點就是:用公鑰加密,用私鑰解密,私鑰要做好保密。
RSA算法的原理可以參照阮一峰的博文:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html 和 http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
安全信道協商流程
我們選擇使用RSA加密算法建立安全信道,在介紹具體方法之前,我們先約定幾個術語:
- C表示客戶端(Client)
- S表示服務端(Server)
- priKey表示私鑰(PrivateKey)
- pubKey表示公鑰(PublicKey)
下面分步驟對流程進行詳細描述。
前提說明
在安全信道建立之前,客戶端和服務端已經擁有一套公私鑰對,公鑰由客戶端持有,私鑰由服務端持有。這里的公私鑰分別表示為:pubKey0和priKey0.
C->S傳遞pubKey
- 客戶端生成一對公私鑰,分別表示為pubKeyC和priKeyC,其中priKeyC客戶端自己持有,pubKeyC需要傳遞給服務端;
- 客戶端使用pubKey0對pubKeyC進行加密,然后通過TCP鏈路將加密后的數據傳輸給服務端;(這個過程我們稱為Stage1)
- 服務端收到客戶端加密的信息后,使用priKey0對信息進行解密,得到pubKeyC.
S->C傳遞pubKey
- 服務端生成一對公私鑰,分別表示為pubKeyS和priKeyS,其中priKeyS服務端自己持有,pubKeyS需要傳遞給客戶端;
- 服務端使用pubKeyC對pubKeyS進行加密,然后通過TCP鏈路將加密后的數據傳輸給客戶端;(這個過程我們稱為Stage3)
- 客戶端收到服務端加密的信息后,使用priKeyC對信息進行解密,得到pubKeyS.
加密通信
經過上述全雙工的加密協商過程,客戶端和服務端之間就建立了使用RSA算法進行加密的通信信道,后續的數據傳輸就是在上述安全信道下進行的。具體如下:
- C-->S的數據,在C端加密,在S端解密,使用的是由服務端初始化生成的公私鑰對(pubKeyS和priKeyS);
- S-->C的數據,在S端加密,在C端解密,使用的是由客戶端初始化生成的公私鑰對(pubKeyC和priKeyC).
工程實踐中的一些優化點
盡量降低初始化私鑰priKey0泄漏風險
上述公私鑰協商過程的安全性是建立在初始化私鑰,即服務端所持有的priKey0未泄漏的基礎上的。如果priKey0泄漏了,那么理論上這個”安全“信道就不安全了。一般工程實踐中,會通過2中方式去盡量降低私鑰泄漏風險:
- 將初始化公私鑰對從一對擴展到多對,在Stage1的過程中,選擇某一個公鑰對數據進行加密,同時將公鑰索引追加到傳遞給服務端的信息中去。服務端在收到信息后先解析出索引,然后取出對應的私鑰進行解密;
- 不定期的更新公私鑰對,這種方案會有一定的弊端,服務端需要同時維護針對不同客戶端版本的私鑰信息,並且還要額外增加一個字段標識服務端使用那對私鑰進行解密,不過可以通過控制客戶端版本數量的方式,將維護成本降低,如維護2個版本客戶端,其他版本強制退出。
服務端Stage3初始化公私鑰性能
對於客戶端來說,每次建立安全通道,單個客戶端只需要進行一次公私鑰對的初始化計算,性能不是瓶頸。但是,對於服務端來說,尤其是接入層,服務了眾多TCP長連接,如果頻繁的進行公私鑰對的初始化計算,CPU性能的消耗成本是巨大的。所以一般工程實踐中,會選擇一種更為理性的方案。
具體做法可以是:
- 在服務端啟動的時候,預先初始化多對公私鑰對,如可以初始化128對或者更多,然后將這些公私鑰對保存在內存中。
- 在Stage3階段,服務端不即時生成公私鑰對,只需要隨機選擇一個內存中的一對公私鑰,並進行加密操作,將對應的公鑰傳遞給客戶端即可。
以上,就是本文的所有內容,期望大家看了之后能有所收獲,謝謝大家!