面試官:你了解數據安全傳輸嗎?
看到這個標題,很多老鐵會斬釘截鐵的說,這道題我會!就是用 HTTPS 來進行安全傳輸的。
對,很優秀,那你知道 HTTPS 底層是如何對數據進行安全保障的嗎?下面就進入我們今天的主題介紹:HTTPS 是如何實現數據安全傳輸的。
HTTPS 認知
HTTPS 其實是 HTTP + SSL 協議組成的安全協議。
我們知道,從我們輸入 URL 到頁面呈現的過程是作用于 HTTP 協議的,HTTP 協議保證我們網絡傳輸數據的基礎,但是安全性無法保證,而 SSL 協議作用于 Http 協議就能解決安全問題。
HTTPS 保證以下三點:
- 數據內容加密
- 數據完整性保護(數字摘要、數字簽名)
- 身份認證
HTTPS 保證安全性要點:
- 握手階段:使用 非對稱加密技術 對 公鑰 進行加密
- 傳輸階段:使用 對稱加密技術 對 報文 進行加密
由于 HTTPS 多了一層使用非對稱加密算法對公鑰進行加密的過程,因此建立連接的時間比 HTTP 要慢。
握手階段保證了連接是安全的,那么后續的數據傳輸就可以安全的進行傳輸,因此可采用耗時較少的對稱加密算法對報文進行加密傳輸。
HTTPS 解構:
在上圖中,我們看到 SSL 協議的作用,在了解保證數據安全的 SSL 協議之前,我們先了解一些關于數據安全涉及的一些概念。
加解密相關概念
1. 對稱加密
別名: 私鑰加密、單密鑰算法、傳統密碼算法。
概念: 指使用 相同的密鑰 進行加解密,因此從加密密鑰可以推算出解密密鑰,也可以從解密密鑰推算出加密密鑰。
常見的對稱加密算法: DES(Data Encryption Standard)、AES(Advanced Encryption Standard)、RC4、IDEA
2. 非對稱加密
別名: 公鑰加密
概念: 公鑰是對外公開的,私鑰存儲在通信兩端的各自手里。客戶端跟加密的公鑰形成一對密鑰對, 服務端跟加密的公鑰形成另外一對密鑰對,加解密的密鑰是成對的
限制: 加密內容的長度不能超過公鑰的長度
3. 數字摘要
別名: 數字指紋
概念: 明文采用單項 Hash 函數生成的一串固定長度(128 位)的密文。
4. 數字簽名
概念:非對稱密鑰加密技術和數字摘要的混合應用
(1) 數字簽名過程
- 發送者使用 Hash 函數 (H) 將原文生成數字摘要 A
- 發送者使用自己的私鑰, 對數字摘要 A 進行加密, 生成密文 CypherA
- 將密文 CypherA 與原文一起傳送給接收者
(2) 數字簽名驗證(信息的完整性)過程
- 接收者使用 Hash 函數 (H) 將接收到的原文生成數字摘要 B (B === A, H 函數是一樣的)
- 接收者使用公鑰,對接收到的加密密文 (CypherA) 進行解密, 得到數字摘要 B'
- 對比 B' 與 B 是否相等, 如果相等,說明收到的信息是完整的并且消息確實是由該發送方簽名并發送的(因為私鑰只有發送方自己知道),在傳輸過程中沒有被修改;否則信息被修改
最后比較數字摘要 A 與數字摘要 A'是否相等,也可以逆向使用 Hash()函數,將摘要 A'進行還原得到明文,比較改明文與傳過來的原文是否一致(都是 pig)。
數字簽名是個加密的過程,數字簽名驗證 是個解密的過程。一次數字簽名涉及到一個哈希函數、接收者的公鑰、發送方的[私鑰]。
(3) 偽代碼
- // 單項 Hash 函數
- fucntion Hash (plainText) { // 傳入明文參數
- // 明文加密過程
- const encryptencryptedAbstract = encrypt(plainText)
- // 返回固定長度(128 位)的數字摘要
- return encryptedAbstract
- }
- // 發送者使用自己的私鑰對明文產生的數字摘要進行加密, 生成密文 CypherA
- function doEncrypt (senderPrivateKey, encryptedAbstract) {
- const CypherA = encrypt(senderPrivateKey, encryptedAbstract)
- return CypherA
- }
- // 發送報文
- function sendMessage (plainText) {
- const encryptedAbstract = Hash(plainText)
- const CypherA = doEncrypt(senderPrivateKey, encryptedAbstract) // 加密
- return {
- CypherText: CypherA,
- originText: plainText
- }
- }
- // 接收者用公鑰解密
- function doDecrypt (publicKey, encryptedAbstract) {
- const decryptdecryptedAbstract = decrypt(publicKey, encryptedAbstract)
- return decryptedAbstract
- }
- // 接收報文
- function receiveMessage (CypherA, plainText) {
- const encryptedAbstract = Hash(plainText)
- const decryptedAbstract = doDecrypt(publicKey, encryptedAbstract) // 解密
- if (decryptedAbstract === encryptedAbstract) {
- console.log('1、the sender is true') // 消息發送者的確認
- console.log('2、the message is complete') // 消息完整性的確認
- }
- }
- const message = sendMessage(plainText) // 數字簽名過程
- receiveMessage (message.CypherText, message.originText) // 數字簽名認證過程
5. 數字證書
在上述數字簽名的過程中,我們如何保證這個公鑰是可信任的?這就是數字證書存在的必要性。
數字證書主要用于加密、簽名、身份認證。
數字證書由證書頒發機構(CA, Certification Agent) 頒發, CA 會在頒發證書之前以及使用證書時對持有者的身份進行驗證,它讓客戶端有能力去識別公鑰是否來自合法的服務器。
證書頒發機構(CA) 頒發包含公鑰和所有者身份的數字證書。匹配的私鑰不是公開的,而是由生成密鑰對的最終用戶保密。證書還是 CA 的確認或驗證,證書中包含的公鑰屬于證書中標注的個人,組織,服務器或其他實體。CA 在此類方案中的義務是驗證申請人的憑證,以便用戶和信賴方可以信任 CA 證書中的信息。
當您訪問使用 HTTPS(安全連接)的網站時,該網站的服務器會使用證書向瀏覽器(如 Chrome)證明該網站的身份。證書中包含的公鑰信息是可信任的, 如果證書不存在、證書被篡改、證書失效等情況,瀏覽器會在左上角提示你該網站不安全。
簽名驗證鏈條:client <- 服務器 <- CA
數字證書的內容:
- 證書頒發機構的名稱
- 證書本身的數字簽名
- 證書持有者公鑰
- 證書簽名用到的 Hash 算法
- ... 等等
公鑰和數字簽名
了解這些基本概念后, 進入我們今天的主題:SSL 協議如何保障數據安全傳輸。
SSL/TLS
1. SSL(Secure Socket Layer, 安全套接字層)
利用加密技術,確保數據在網絡傳輸過程中不會被竊取。
2. TLS (Transport Layer Security,傳輸層安全協議)
用于兩個應用程序之間提供保密性和數據完整性。
該協議建立在 SSL3.0 協議的基礎之上,可理解為 SSL3.1 版本。只不過在 SSL3.0 的基礎上采用了一些更安全的策略,讓數據更加安全,其他的協議分層與功能與 SSL 一致。有興趣的可自行了解其與 SSL 的區別與優勢。
SSL/TLS 協議的作用:
- 數據加密,防止被竊取
- 保護數據的完整性,確保數據不會被改變
- 身份認證,確保數據被發送到正確的客戶端和服務器
可以看到, 這正是 HTTPS 協議發揮作用的三點。
那么, SSL 協議到底是如何把我們數據進行加密,從而進行安全傳輸的呢?
3. SSL、TLS 的握手過程
(1) 客戶端告知服務端自己支持的 安全協議版本(如 TLS1.0)、加密算法、壓縮方法、隨機數 CRandom1;
(2) 服務端首次響應,返回給客戶端 安全協議的版本、加密算法、壓縮方法、隨機數 SRandom, 還有一個 數字證書(服務器證書);
(3) 客戶端對服務端發送過來的證書進行驗證,驗證通過后,進行如下操作:
- 客戶端再次產生一個隨機數 CRandom2
- 使用服務器證書中的公鑰對數據進行進行加密,生成隨機數 CRandom3
- 發送 ChangeCipherSpec(編碼改變)的消息通知(告知服務器我已經準備好用我們之前商量好的加密套件進行加密并傳輸數據了) 、前面 所有消息的 hash 值 以及 加密數據 CRandom3 進行服務器驗證
- 使用與服務器確認的加密算法對 CRandom1、CRandom2、CRandom3 三個隨機數進行加密,生成 Session Secret(這個就是后邊使用對稱加密算法進行傳輸數據時所用到的對稱加密密鑰,還可用來 會話恢復, 節約 SSL 的握手時間)
(4) 服務器再次響應:
- 使用自己的私鑰對 CRandom3 進行解密、并對解密后的數據進行驗證
- 發送 ChangeCipherSpec(編碼改變)的消息通知(告知客戶端我也準備好了用我們之前商量好的加密套件和 Session Secret 進行加密數據了)
- 使用 Session Secret 加密一段 Finish 的消息發送給客戶端, 以驗證之前通過握手建立起來的加解密通道是否成功
到上面四步,客戶端與服務器已經確定了密鑰,就可以對消息進行加密傳輸了。
到此,握手過程結束。
整個握手階段的安全,取決于第三個隨機數 CRandom3 能否被破解,因為這個隨機數是使用服務端的公鑰進行加密的、服務端的私鑰進行解密的;而私鑰只存儲在了服務端本身。
在所有的握手階段都完成之后,就可以使用對稱加密技術開始傳送應用數據了。
QA
1. 客戶端如何對接收到的證書進行驗證的?
證書本身就已經告訴客戶端怎么驗證證書的真偽。也就是證書上寫著如何根據證書的內容生成證書編號。客戶端拿到證書后根據證書上的方法自己生成一個證書編號,如果生成的證書編號與證書上的證書編號相同,那么說明這個證書是真實的。
2. 公鑰的安全性是通過證書來確認的, 但是證書是由頒發機構來頒發的, 那如何確認這個頒發者是可信的呢?
通過證書鏈。
- root:根證書,權威證書認證機構 (CA, Certificate Authority) 給自己頒發的數字證書,也就是自己認證自己。在上圖中根證書就是由 DigiCert Global Root CA 自己給自己簽發的。
- intermediates:中間證書,根 CA 生成一對公鑰、私鑰,并用私鑰將中間 CA 的信息和公鑰進行 “加密” 生成簽名,封裝得到中間證書。需要注意的是,中間 CA 可能不止一個。上一級 CA 同樣按照這個邏輯給下一級 CA 進行簽發證書。在這里中間 CA 就是 RapidSSL RSA CA 2018,它給末端使用者簽發證書。
- end-user:末端使用者(證書)。圖中的末端證書就是 *.juejin.im 使用的數字證書。
可以看到證書鏈由多個證書一層一層組成的。末端證書的公鑰是給用戶加密報文外,其他層證書中的公鑰均用于解密下一層的證書指紋簽名。最高層的根證書是自簽名的,也就是自己頒發給自己,所以 根證書一定是可信的(難道自己還不能信任自己嗎?^^)
總結
網絡安全傳輸數據依賴 SSL 協議,而網絡傳輸的協議是 HTTP, 因此構成了 HTTPS 協議。而 HTTPS 要保證客戶端與服務器端的高效通信安全,必須使用對稱加密算法,但是協商對稱加密算法的過程,需要使用非對稱加密算法來保證安全,然而直接使用非對稱加密的過程本身也不安全,會有中間人篡改公鑰的可能性,所以客戶端與服務器不直接使用公鑰,而是使用數字證書簽發機構頒發的證書來保證非對稱加密過程本身的安全。
這樣通過這些機制協商出一個對稱加密算法,就此雙方使用該算法對數據進行加密解密傳輸,從而解決了客戶端與服務器端之間的通信安全問題。