完全理解 HTTPS 如何做到傳輸安全
原 作 者:fi3ework
原文鏈接:https://github.com/fi3ework/blog/issues/17
概念
HTTPS:是以安全為目標的 HTTP 通道,簡單講是 HTTP 的安全版,即 HTTP 下加入 SSL 層,HTTPS 的安全基礎是 SSL,因此加密的詳細內容就需要 SSL。
HTTPS 協議的主要作用可以分為兩種:一種是建立一個信息安全通道,來保證數據傳輸的安全;另一種就是確認網站的真實性。
名詞解釋
公鑰(yuè)私鑰(yuè)
公開密鑰加密(英語:Public-key cryptography),也稱為非對稱加密(英語:asymmetric cryptography),是 密碼學[1] 的一種 算法[2],它需要兩個密鑰[3],一個是公開密鑰,另一個是私有密鑰;一個用作加密的時候,另一個則用作解密。使用其中一個密鑰把明文[4] 加密后所得的密文[5],只能用相對應的另一個密鑰才能解密得到原本的明文;甚至連最初用來加密的密鑰也不能用作解密。由于加密和解密需要兩個不同的密鑰,故被稱為非對稱加密;不同于加密和解密都使用同一個密鑰的對稱加密[6]。雖然兩個密鑰在數學上相關,但如果知道了其中一個,并不能憑此計算出另外一個;因此其中一個可以公開,稱為公鑰,任意向外發布;不公開的密鑰為私鑰,必須由用戶自行嚴格秘密保管,絕不通過任何途徑向任何人提供,也不會透露給要通信的另一方,即使他被信任。
以上是來自維基百科的公鑰私鑰的定義,HTTPS 是基于非對稱加密的,公鑰和私鑰是整個 HTTPS 的基礎。簡單來說,公鑰是公開的(要不叫公鑰),比如小 A 想給我發送加密信息就要他我的公鑰,讓他用我的公鑰對信息進行加密,這個信息只有我的私鑰能打開。所以私鑰是絕對不能泄漏的,那么私鑰只能用來解開公鑰嗎?并不是,公鑰私鑰都可以加密和用對方來解密,私鑰用來簽發數字簽名,我用獨一無二的私鑰簽發了一個數字簽名,你們都有我的公鑰,只有我簽發的數字簽名能用我的公鑰解開,才能證明這個簽名發自我。
知乎上有個回答特別精辟:
不要去硬記。 你只要想:既然是加密,那肯定是不希望別人知道我的消息,所以只有我才能解密,所以可得出公鑰負責加密,私鑰負責解密;同理,既然是簽名,那肯定是不希望有人冒充我發消息,只有我才能發布這個簽名,所以可得出私鑰負責簽名,公鑰負責驗證。
Diffie--Hellman
迪菲 - 赫爾曼密鑰交換(英語:Diffie--Hellman key exchange,縮寫為 D-H) 是一種 安全協議[7]。它可以讓雙方在完全沒有對方任何預先信息的條件下通過不安全信道[8] 創建起一個 密鑰[9]。這個密鑰可以在后續的通訊中作為對稱密鑰[10] 來加密[11]通訊內容。
筆者本人并沒很仔細理解這個算法的原理,但是作為前端在實際應用中只需要知道這個加密算法的作用就好了,中間就是黑箱。簡單來說這個算法的作用就是:Alice 和 Bob 各自有對方的公鑰(當然其他人也有),Alice 和 Bob 再產生一個隨機數(不告訴別人),然后用兩個人的公鑰和自己手里的隨機數產生兩個數 A B,然后它們交換這兩個數,每個人可以用自己手頭的隨機數和交換得來的數再次計算,兩個人得到的數是一樣的,就得到了一個共享密鑰。
在 知乎[12] 上找到一個這個共享秘鑰計算過程的描述
- Alice 與 Bob 確定兩個大素數 n 和 g,這兩個數不用保密
- Alice 選擇另一個大隨機數 x,并計算 A 如下:A=gxmod n
- Alice 將 A 發給 Bob
- Bob 選擇另一個大隨機數 y,并計算 B 如下:B=gymod n
- Bob 將 B 發給 Alice
- 計算秘密密鑰 K1 如下:K1=Bxmod n
- 計算秘密密鑰 K2 如下:K2=Aymod n K1=K2,因此 Alice 和 Bob 可以用其進行加解密
因此,client 和 server 可以 "離線" 計算出一份只有對方知道的秘鑰。
數字證書
公開密鑰認證(英語:Public key certificate),又稱公開密鑰證書、公鑰證書、數字證書(digital certificate)、數字認證、身份證書(identity certificate)、電子證書或安全證書,是用于 公開密鑰基礎建設[13] 的電子文件,用來證明 公開密鑰[14] 擁有者的身份[15]。此文件包含了公鑰信息、擁有者身份信息(主體)、以及數字證書認證機構[16](發行者)對這份文件的數字簽名[17],以保證這個文件的整體內容正確無誤[18]。
包含的內容有:
版本:現行通用版本是 V3
序號:用以辨識每一張證書,特別在撤消證書的時候有用
主體:擁有此證書的法人或自然人身份或機器,包括:
國家(C,Country)
州 / 省(S,State)
地域 / 城市(L,Location)
組織 / 單位(O,Organization)
通用名稱(CN,Common Name):在 TLS 應用上,此字段一般是網域
發行者:以數字簽名形式簽署此證書的數字證書認證機構
有效期開始時間:此證書的有效開始時間,在此前該證書并未生效
有效期結束時間:此證書的有效結束時間,在此后該證書作廢
公開密鑰用途:指定證書上公鑰的用途,例如數字簽名、服務器驗證、客戶端驗證等
公開密鑰
公開密鑰指紋
數字簽名
數字簽名算法
主體別名:例如一個網站可能會有多個網域(www.wikipedia.org, zh.wikipedia.org, zh.m.wikipedia.org 都是維基百科)、一個組織可能會有多個網站(_.wikipedia.org, _.wikibooks.org, *.wikidata.org 都是維基媒體基金會旗下的網域),不同的網域可以一并使用同一張證書,方便實現應用及管理
其中,在加密過程中最重要的是公開密鑰和數字簽名算法,前者用來生成 session key,后者是驗算 hash 的方法。
CA
數字證書認證機構(英語:Certificate Authority,縮寫為 CA),也稱為電子商務認證中心、電子商務認證授權機構,是負責發放和管理數字證書的權威機構,并作為電子商務交易中受信任的第三方,承擔公鑰體系中公鑰的合法性檢驗的責任。
在 CA 給服務端頒發證書的同時會產生一個私鑰和公鑰。私鑰由服務端自己保存,不可泄漏。公鑰則是附帶在證書的信息中,可以公開的。證書本身也附帶一個證書電子簽名,這個簽名用來驗證證書的完整性和真實性,可以防止證書被串改。
流程
SSL 協議分為兩部分:Handshake Protocol 和 Record Protocol。其中 Handshake Protocol 用來協商密鑰,協議的大部分內容就是通信雙方如何利用它來安全的協商出一份密鑰。 Record Protocol 則定義了傳輸的格式。
相比對稱加密,非對稱加密的速度比較慢,所以它一般用于密鑰交換,雙方通過公鑰算法協商出一份密鑰,然后通過這個密鑰對稱加密來通信,充分結合這兩者的優勢。
STEP 1: ClientHello
首先,由客戶端向服務端發起一個明文的無保護的請求,用來初始化 SSL(這里的客戶端只是一個職責的代號,代表 "首先發送信息的一方",對前端來說,就是瀏覽器)。
messageclinet +---------------> server
message 中包含以下內容:
- 客戶端最高能支持的協議
- 一個隨機數,稱為 client_random
- session ID(以防客戶端想在握手階段回復 session)
- 客戶端支持的 cipher suite[19]
- 客戶端支持的壓縮方法
- 一些其他信息
這個隨機數是會在后面中用到的,其他的是用來標明客戶端支持的特性的。
STEP 2: ServerHello
ServerHello Certificate* ServerKeyExchange* CertificateRequest* ServerHelloDoneclinet <---------------------+ server
服務端收到客戶端發來的信息,返回給客戶端自己的信息,message 中包括
- 客戶端和服務端將使用的協議
- 一個隨機數,稱為 server_random
- 這次會話的 session ID
- 雙方將會使用的 cipher suite
- 雙方將會使用的壓縮方法
- 服務器的證書 + 數字簽名(證書中包含服務端的公鑰)
- ServerKeyExchange: 在服務端向客戶端發送的證書中沒有提供足夠的信息(證書公鑰)的時候,用來驗證身份。
- ServerHelloDone(表示 Server Hello 完成)
這里要說一下數字證書與數字簽名,數字證書這個東西是向第三方機構去申請的。
數字簽名用來保證數字證書沒有被篡改過,因為數字簽名是用 CA 的私鑰來加密的,如果第三方篡改了簽名是無法用 CA 的公鑰解密的(就偽裝不下去了),數字簽名也是 CA 給的。
數字簽名的過程如下,使用證書中的數字簽名算法計算證書的一個 HASH 值,然后 CA 用私鑰給加密,然后給服務端,服務端保管好即可。
數字簽名算法 CA 私鑰加密數字證書 +-------------> HASH +-------------> 數字簽名
最后服務器發送 Server Hello Done 報文通知客戶端, 最初階段的 SSL 握手協商部分結束,客戶端應該發送信息了。
STEP 3: 客戶端回應
驗證證書
client:+---------------------------------------------------------------------+| CA 公鑰解密 || 數字簽名 +--------------------> 服務端的 HASH +-----+ || | || +-----> 是否相同 || 數字證書中的數字簽名算法 | || 數字證書 +--------------------> 客戶端計算的 HASH +-- + || |+----------------------------------------------------------------------+
客戶端根據證書中的數字簽名算法計算出數字證書的 HASH,再用本地的 CA 公鑰(瀏覽器廠商會內置根證書,可以通過證書鏈將服務端的證書用內置的根證書認證)。解密出數字簽名的 HASH,比較一致則表明這確實是未被篡改過的數字證書。到這一步,客戶端已經成功拿到了服務端的證書。
回應服務端
Certificate* ClientKeyExchange CertificateVerify* [ChangeCipherSpec] Finishedclinet +---------------------> server
證書
客戶端的證書,如果服務端需要的話會發送(比如某些網銀需要 U 盾來生成證書驗證客戶端的身份)。
ClientKeyExchange
如果服務端需要對客戶端進行驗證,在客戶端收到服務端的 Server Hello 消息之后,首先需要向服務端發送客戶端的證書,讓服務端來驗證客戶端的合法性。
CertificateVerify
如果證書沒有問題,客戶端就會從服務器證書中取出服務器的公鑰來加密以下信息回應服務端:
- 一個隨機數。該隨機數用服務器公鑰加密,防止被竊聽(稱為 pre-master key)
- 編碼改變通知,表示隨后的信息都將用雙方商定的加密方法和密鑰發送
- 客戶端握手結束通知,表示客戶端的握手階段已經結束。這一項同時也是前面發送的所有內容的 hash 值,用來供服務器校驗
ChangeCipherSpec
ChangeCipherSpec 是一個獨立的協議,體現在數據包中就是一個字節的數據,用于告知服務端,客戶端已經切換到之前協商好的加密套件(Cipher Suite)的狀態,準備使用之前協商好的加密套件加密數據并傳輸了。它標志著從客戶端之后發出的信息將使用 shared secret 來進行加密。
Finished
在 ChangecipherSpec 傳輸完畢之后,客戶端會使用之前協商好的加密套件和 shared secret 加密一段 Finish 的數據傳送給服務端,此數據是為了在正式傳輸應用數據之前對剛剛握手建立起來的加解密通道進行驗證。
STEP 4: 服務端回應
[ChangeCipherSpec] Finishedclinet <---------------------+ server
在這一步,服務端無論如何將得到 pre-master key,但是 SSL 有幾種不同的交換密鑰的算法,由 cipher suite 來決定,每種密鑰交換算法需要不同的公鑰來推倒,這里介紹兩種:
- RSA:服務端的加密方式為 RSA,客戶端產生一個隨機數,就上上一步中的 pre-master key,然后用服務端的公鑰加密,如果是這樣的話就不需要傳輸 ServerKeyExchange。
- DHE_RSA:服務端的加密方式為 RSA,不過只是用來簽名。真正需要的密鑰是用上面介紹的 DH 算法推倒的。ServerKeyExchange 中包含 DH 需要的參數和一個更新過的 DH 公鑰,然后服務端對其進行加密發送給客戶端。客戶端更新這個 DH 公鑰返回給 服務端。這個 DH 公鑰會產生 pre-master key。
不管用哪種方法,服務端和客戶端現在都已經持有 pre-master key 后,使用私鑰進行解密獲得 pre-master key。再加上自己手上的 server_random 和 client_random,然后客戶端和服務端會使用一個 PRF (Pseudo-Random Function) 算法來產生 master-secret。
master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)
再由 master-secret 推導出 session-key(也稱 shared-secret),這是雙方后續通信用來最終加密的對稱密鑰。
一切準備好之后,服務端也回應客戶端一個自己的用 session-key 加密的 ChangeCipherSpec,標明自己之后的信息也將使用 session-key 來加密。之后,服務端也會使用 session-key 加密一段 Finish 消息發送給客戶端,以驗證之前通過握手建立起來的加解密通道是否成功。
STET 6: HTTPS 通信
根據之前的握手信息,服務器和客戶端的 Finished 報文交換完畢之后,如果客戶端和服務端都能對 Finish 信息進行正常加解密且消息正確的被驗證,則說明 SSL 連接就算建立完成。接下來,雙方可以進行應用層的通信,使用上面產生的 session-key 對 HTTP 進行加密傳輸了。
在以上流程中, 應用層發送數據時會附加一種叫做 mac( Message Authentication Code) 的報文摘要。 MAC 能夠查知報文是否遭到篡改, 從而保護報文的完整性。
總結
最后放上一張圖來總結整個 SSL 的過程,其中加密方式采用的是 RSA,但是整個流程是思路是一致的。
其實 HTTPS 要復雜的多,本文介紹的過程是簡化了的,主要是理清如何安全獲得對稱公鑰。
via The SSL/TLS Handshake: an Overview[20]

ssltls_handshake
GOOD & BAD
放上 HTTPS 的好處與壞處,via https 是什么?使用 https 的好處與不足?[21]
好處
正是由于 HTTPS 非常的安全,攻擊者無法從中找到下手的地方,從站長的角度來說,HTTPS 的優點有以下 2 點:
- seo 方面
谷歌曾在 2014 年 8 月份調整搜索引擎算法,并稱 "比起同等 HTTP 網站,采用 HTTPS 加密的網站在搜索結果中的排名將會更高"。 - 安全性
盡管 HTTPS 并非絕對安全,掌握根證書的機構、掌握加密算法的組織同樣可以進行中間人形式的攻擊,但 HTTPS 仍是現行架構下最安全的解決方案,主要有以下幾個好處: 使用 HTTPS 協議可認證用戶和服務器,確保數據發送到正確的客戶機和服務器;HTTPS 協議是由 SSL + HTTP 協議構建的可進行加密傳輸、身份認證的網絡協議,要比 HTTP 協議安全,可防止數據在傳輸過程中不被竊取、改變,確保數據的完整性。HTTPS 是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增加了中間人攻擊的成本。
不足
雖然說 HTTPS 有很大的優勢,但其相對來說,還是有些不足之處的,具體來說,有以下 2 點:
- SEO 方面
據 ACM CoNEXT 數據顯示,使用 HTTPS 協議會使頁面的加載時間延長近 50%,增加 10% 到 20% 的耗電,此外,HTTPS 協議還會影響緩存,增加數據開銷和功耗,甚至已有安全措施也會受到影響也會因此而受到影響。 而且 HTTPS 協議的加密范圍也比較有限,在黑客攻擊、拒絕服務攻擊、服務器劫持等方面幾乎起不到什么作用。 最關鍵的,SSL 證書的信用鏈體系并不安全,特別是在某些國家可以控制 CA 根證書的情況下,中間人攻擊一樣可行。 - 經濟方面 SSL 證書需要錢,功能越強大的證書費用越高,個人網站、小網站沒有必要一般不會用。SSL 證書通常需要綁定 IP,不能在同一 IP 上綁定多個域名,IPv4 資源不可能支撐這個消耗(SSL 有擴展可以部分解決這個問題,但是比較麻煩,而且要求瀏覽器、操作系統支持,windows XP 就不支持這個擴展,考慮到 XP 的裝機量,這個特性幾乎沒用)。HTTPS 連接緩存不如 HTTP 高效,大流量網站如非必要也不會采用,流量成本太高。HTTPS 連接服務器端資源占用高很多,支持訪客稍多的網站需要投入更大的成本,如果全部采用 HTTPS,基于大部分計算資源閑置的假設的 VPS 的平均成本會上去。HTTPS 協議握手階段比較費時,對網站的相應速度有負面影響,如非必要,沒有理由犧牲用戶體驗。
參考
- RSA 的公鑰和私鑰到底哪個才是用來加密和哪個用來解密?[22]
- Diffie-Hellman 密碼交換是如何運作的?[23]
- 迪菲 - 赫爾曼密鑰交換[24]
- 公開密鑰認證[25]
- SSL/TLS 原理詳解[26]
- https 的 pre-master-secret 到 master-secret 的過程?[27]
- Differences between the terms 'pre-master secret', 'master secret', 'private key', and 'shared secret'?[28]
- How does SSL/TLS work?[29]
- What's the point of the pre-master key? [duplicate][30]
- The SSL/TLS Handshake: an Overview[31]
- 圖解 HTTP
關注我
大家好,這里是 FEHub,每天早上 9 點更新,為你嚴選優質文章,與你一起進步。
如果喜歡這篇文章,記得點贊,轉發。讓你的好基友和你一樣優秀。
微信后臺回復關鍵字:「092c388d6169e78d」,即可參與紅包抽獎,每晚 10 點開獎。
- 感謝大家的支持
- 吃飯時加個雞腿
- 咱們明天見 & emsp;:)
歡迎關注 「FEHub」,每天進步一點點
推薦閱讀
- 窺探原理:2020 年如何手寫一個類 WebPack 的 JAVAScript 打包器?
- 看完這些 css 的技巧,我才知道什么叫做交互,UED 都自愧不如~
- 「阿里 UC 團隊」如何在 10 分鐘內,徹底搞懂前端頁面性能監控?
參考資料
[1]
密碼學: https://zh.wikipedia.org/wiki/%E5%AF%86%E7%A2%BC%E5%AD%B8
[2]
算法: https://zh.wikipedia.org/wiki/%E6%BC%94%E7%AE%97%E6%B3%95
[3]
密鑰: https://zh.wikipedia.org/wiki/%E5%AF%86%E9%92%A5
[4]
明文: https://zh.wikipedia.org/wiki/%E6%98%8E%E6%96%87
[5]
密文: https://zh.wikipedia.org/wiki/%E5%AF%86%E6%96%87
[6]
對稱加密: https://zh.wikipedia.org/wiki/%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86
[7]
安全協議: https://zh.wikipedia.org/wiki/%E5%AE%89%E5%85%A8%E5%8D%8F%E8%AE%AE
[8]
信道: https://zh.wikipedia.org/wiki/%E4%BF%A1%E9%81%93
[9]
密鑰: https://zh.wikipedia.org/wiki/%E5%AF%86%E9%92%A5
[10]
對稱密鑰: https://zh.wikipedia.org/wiki/%E5%AF%B9%E7%A7%B0%E5%AF%86%E9%92%A5
[11]
加密: https://zh.wikipedia.org/wiki/%E5%8A%A0%E5%AF%86
[12]
知乎: https://www.zhihu.com/question/29383090
[13]
公開密鑰基礎建設: https://zh.wikipedia.org/wiki/%E5%85%AC%E9%96%8B%E9%87%91%E9%91%B0%E5%9F%BA%E7%A4%8E%E5%BB%BA%E8%A8%AD
[14]
公開密鑰: https://zh.wikipedia.org/wiki/%E5%85%AC%E5%BC%80%E5%AF%86%E9%92%A5%E5%8A%A0%E5%AF%86
[15]
身份: https://zh.wikipedia.org/wiki/%E8%BA%AB%E5%88%86%E6%A0%87%E8%AF%86%E6%96%B9%E5%BC%8F
[16]
數字證書認證機構: https://zh.wikipedia.org/wiki/%E6%95%B0%E5%AD%97%E8%AF%81%E4%B9%A6%E8%AE%A4%E8%AF%81%E6%9C%BA%E6%9E%84
[17]
數字簽名: https://zh.wikipedia.org/wiki/%E6%95%B8%E4%BD%8D%E7%B0%BD%E7%AB%A0
[18]
正確無誤: https://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E5%AE%8C%E6%95%B4%E6%80%A7
[19]
cipher suite: https://zh.wikipedia.org/wiki/%E5%AF%86%E7%A0%81%E5%A5%97%E4%BB%B6
[20]
The SSL/TLS Handshake: an Overview: https://tweenpath.net/ssl-tls-handshake-overview/
[21]
https 是什么?使用 https 的好處與不足?: http://www.shuchengxian.com/article/634.html
[22]
RSA 的公鑰和私鑰到底哪個才是用來加密和哪個用來解密?: https://www.zhihu.com/question/25912483
[23]
Diffie-Hellman 密碼交換是如何運作的?: https://www.zhihu.com/question/29383090
[24]
迪菲 - 赫爾曼密鑰交換: https://zh.wikipedia.org/wiki/%E8%BF%AA%E8%8F%B2-%E8%B5%AB%E7%88%BE%E6%9B%BC%E5%AF%86%E9%91%B0%E4%BA%A4%E6%8F%9B
[25]
公開密鑰認證: https://zh.wikipedia.org/wiki/%E5%85%AC%E9%96%8B%E9%87%91%E9%91%B0%E8%AA%8D%E8%AD%89
[26]
SSL/TLS 原理詳解: https://www.linuxidc.com/Linux/2016-05/131147.htm
[27]
https 的 pre-master-secret 到 master-secret 的過程?: https://www.zhihu.com/question/54320042
[28]
Differences between the terms 'pre-master secret', 'master secret', 'private key', and 'shared secret'?: https://crypto.stackexchange.com/questions/27131/differences-between-the-terms-pre-master-secret-master-secret-private-key
[29]
How does SSL/TLS work?: https://security.stackexchange.com/questions/20803/how-does-ssl-tls-work
[30]
What's the point of the pre-master key? [duplicate]: https://security.stackexchange.com/questions/54399/whats-the-point-of-the-pre-master-key
[31]
The SSL/TLS Handshake: an Overview: https://tweenpath.net/ssl-tls-handshake-overview/