熟悉了對稱加密與非對稱加密、數字簽名與證書等密碼學知識。就能夠正式開始研究 HTTPS 和 TLS 協議了。算法
當你在瀏覽器地址欄裏鍵入「https」開頭的 URI,再按下回車,會發生什麼呢?瀏覽器
你應該知道,瀏覽器首先要從 URI 裏提取出協議名和域名。由於協議名是「https」,因此瀏覽器就知道了端口號是默認的 443,它再用 DNS 解析域名,獲得目標的 IP 地址,而後就可使用三次握手與網站創建 TCP 鏈接了。安全
在 HTTP 協議裏,創建鏈接後,瀏覽器會當即發送請求報文。但如今是 HTTPS 協議,它須要再用另一個「握手」過程,在 TCP 上創建安全鏈接,以後纔是收發 HTTP 報文。bash
這個「握手」過程與 TCP 有些相似,是 HTTPS 和 TLS 協議裏最重要、最核心的部分,懂了它,你就能夠自豪地說本身「掌握了 HTTPS」。服務器
先簡單介紹一下 TLS 協議的組成。dom
TLS 包含幾個子協議,你也能夠理解爲它是由幾個不一樣職責的模塊組成,比較經常使用的有記錄協議、警報協議、握手協議、變動密碼規範協議等。網站
記錄協議(Record Protocol)規定了 TLS 收發數據的基本單位:記錄(record)。它有點像是 TCP 裏的 segment,全部的其餘子協議都須要經過記錄協議發出。但多個記錄數據能夠在一個 TCP 包裏一次性發出,也並不須要像 TCP 那樣返回 ACK。ui
警報協議(Alert Protocol)的職責是向對方發出警報信息,有點像是 HTTP 協議裏的狀態碼。好比,protocol_version 就是不支持舊版本,bad_certificate 就是證書有問題,收到警報後另外一方能夠選擇繼續,也能夠當即終止鏈接。加密
握手協議(Handshake Protocol)是 TLS 裏最複雜的子協議,要比 TCP 的 SYN/ACK 複雜的多,瀏覽器和服務器會在握手過程當中協商 TLS 版本號、隨機數、密碼套件等信息,而後交換證書和密鑰參數,最終雙方協商獲得會話密鑰,用於後續的混合加密系統。spa
變動密碼規範協議(Change Cipher Spec Protocol),它很是簡單,就是一個「通知」,告訴對方,後續的數據都將使用加密保護。那麼反過來,在它以前,數據都是明文的。
下面的這張圖簡要地描述了 TLS 的握手過程,其中每個「框」都是一個記錄,多個記錄組合成一個 TCP 包發送。因此,最多通過兩次消息往返(4 個消息)就能夠完成握手,而後就能夠在安全的通訊環境裏發送 HTTP 報文,實現 HTTPS 協議。
剛纔的是握手過程的簡要圖,這裏有一個詳細圖
在 TCP 創建鏈接以後,瀏覽器會首先發一個「Client Hello」消息,也就是跟服務器「打招呼」。裏面有客戶端的版本號、支持的密碼套件,還有一個隨機數(Client Random),用於後續生成會話密鑰。
Handshake Protocol: Client Hello
Version: TLS 1.2 (0x0303)
Random: 1cbf803321fd2623408dfe…
Cipher Suites (17 suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
複製代碼
服務器收到「Client Hello」後,會返回一個「Server Hello」消息。把版本號對一下,也給出一個隨機數(Server Random),而後從客戶端的列表裏選一個做爲本次通訊使用的密碼套件,在這裏它選擇了「TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384」。
Handshake Protocol: Server Hello
Version: TLS 1.2 (0x0303)
Random: 0e6320f21bae50842e96…
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
複製代碼
這個的意思就是:「版本號對上了,能夠加密,你的密碼套件挺多,我選一個最合適的吧,用橢圓曲線加 RSA、AES、SHA384。我也給你一個隨機數,你也得留着。」
而後,服務器爲了證實本身的身份,就把證書也發給了客戶端(Server Certificate)。
接下來是一個關鍵的操做,由於服務器選擇了 ECDHE 算法,因此它會在證書後發送「Server Key Exchange」消息,裏面是橢圓曲線的公鑰(Server Params),用來實現密鑰交換算法,再加上本身的私鑰簽名認證。
Handshake Protocol: Server Key Exchange
EC Diffie-Hellman Server Params
Curve Type: named_curve (0x03)
Named Curve: x25519 (0x001d)
Pubkey: 3b39deaf00217894e...
Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
Signature: 37141adac38ea4...
複製代碼
這至關於說:「剛纔我選的密碼套件有點複雜,因此再給你個算法的參數,和剛纔的隨機數同樣有用,別丟了。爲了防止別人冒充,我又蓋了個章。」
以後是「Server Hello Done」消息,服務器說:「個人信息就是這些,打招呼完畢。」
這樣第一個消息往返就結束了(兩個 TCP 包),結果是客戶端和服務器經過明文共享了三個信息:Client Random、Server Random 和 Server Params。
客戶端這時也拿到了服務器的證書,那這個證書是否是真實有效的呢?
走證書鏈逐級驗證,確認證書的真實性,再用證書公鑰驗證簽名,就確認了服務器的身份:「剛纔跟我打招呼的不是騙子,能夠接着往下走。」
而後,客戶端按照密碼套件的要求,也生成一個橢圓曲線的公鑰(Client Params),用「Client Key Exchange」消息發給服務器。
Handshake Protocol: Client Key Exchange
EC Diffie-Hellman Client Params
Pubkey: 8c674d0e08dc27b5eaa…
複製代碼
如今客戶端和服務器手裏都拿到了密鑰交換算法的兩個參數(Client Params、Server Params),就用 ECDHE 算法一陣算,算出了一個新的東西,叫「Pre-Master」,其實也是一個隨機數。
如今客戶端和服務器手裏有了三個隨機數:Client Random、Server Random 和 Pre-Master。用這三個做爲原始材料,就能夠生成用於加密會話的主密鑰,叫「Master Secret」。而黑客由於拿不到「Pre-Master」,因此也就得不到主密鑰。
爲何非得這麼麻煩,非要三個隨機數呢?
這就必須說 TLS 的設計者考慮得很是周到了,他們不信任客戶端或服務器僞隨機數的可靠性,爲了保證真正的「徹底隨機」「不可預測」,把三個不可靠的隨機數混合起來,那麼「隨機」的程度就很是高了,足夠讓黑客難以猜想。
有了主密鑰和派生的會話密鑰,握手就快結束了。客戶端發一個「Change Cipher Spec」,而後再發一個「Finished」消息,把以前全部發送的數據作個摘要,再加密一下,讓服務器作個驗證。
意思就是告訴服務器:「後面都改用對稱算法加密通訊了啊,用的就是打招呼時說的 AES,加密對不對還得你測一下。」
服務器也是一樣的操做,發「Change Cipher Spec」和「Finished」消息,雙方都驗證加密解密 OK,握手正式結束,後面就收發被加密的 HTTP 請求和響應了。
上面說的是「單向認證」握手過程,只認證了服務器的身份,而沒有認證客戶端的身份。這是由於一般單向認證經過後已經創建了安全通訊,用帳號、密碼等簡單的手段就可以確認用戶的真實身份。
但爲了防止帳號、密碼被盜,有的時候(好比網上銀行)還會使用 U 盾給用戶頒發客戶端證書,實現「雙向認證」,這樣會更加安全。
雙向認證的流程也沒有太多變化,只是在「Server Hello Done」以後,「Client Key Exchange」以前,客戶端要發送「Client Certificate」消息,服務器收到後也把證書鏈走一遍,驗證客戶端的身份。
內容比較多、比較難,不過記住下面四點就能夠