Http協議
由于 HTTP 協議在通信過程中,是基于明文通信,并且底層是基于 TCP/IP 協議進行通信,那么按照 TCP/IP 協議族的工作機制,通信內容在所有的通信線路上都有可能遭到攔截和竊取。
https 安全傳輸協議
由于 HTTP 協議通信的不安全性,所以人們為了防止信息在傳輸過程中遭到泄漏或者篡改,就想出來對傳輸通道進行加密的方式 https。https 是一種加密的超文本傳輸協議,它與 HTTP 在協議差異在于對數據傳輸的過程中,https對數據做了完全加密。由于 http 協議或者 https 協議都是處于 TCP 傳輸層之上,同時網絡協議又是一個分層的結構,所以在 tcp 協議層之上增加了一層 SSL(Secure Socket Layer,安全層)或者 TLS(Transport Layer Security) 安全層傳輸協議組合使用用于構造加密通道。

推導 https 的設計過程
我們先不去探究 ssl 的實現原理,我們先從設計者的角度去思考如何去建立一個安全的傳輸通道,客戶端 A 向服務端 B 發送一條消息,這個消息可能會被攔截以及篡改,我們如何做到 A 發送給 B 的數據包,即使被攔截了,也沒辦法得知消息內容并且也不能查看呢?

我們首先了解幾個基本概念。
共享密鑰加密(對稱密鑰加密):加密和解密同用一個密鑰。加密時就必須將密鑰傳送給對方。
公開密鑰加密(非對稱密鑰加密):公開密鑰加密使用一對非對稱的密鑰。一把叫做私有密鑰,一把叫做公開密鑰。私有密鑰不能讓其他任何人知道,而公開密鑰則可以隨意發布,任何人都可以獲得。使用此加密方式,發送密文的一方使用公開密鑰進行加密處理,對方收到被加密的信息后,再使用自己的私有密鑰進行解密。利用這種方式,不需要發送用來解密的私有密鑰,也不必擔心密鑰被攻擊者竊聽盜走。
利用對稱加密
要做到消息不能被第三方查看以及篡改,那么第一想法就是對內容進行加密,同時,該消息還需要能被服務端進行解密。所以我們可以使用對稱加密算法來實現,密鑰 S 扮演著加密和解密的角色。在密鑰 S 不公開的情況下,就可以保證安全性?

在互聯網世界里,通信不會這么簡單,會存在多個客戶端和服務端產生連接,而這個客戶端也許是一個潛伏者(黑客),如果他也有對稱密鑰 S,那相當于上面的方案是不可行的。

如果服務端和每個客戶端通信的時候使用不同的加密算法呢?

似乎能夠完美解決問題,然后?密鑰如何分配呢?也就是服務端怎么告訴客戶端該使用哪種對稱加密算法呢?解決辦法似乎只能通過建立會話以后進行協商了。但協商過程又是不安全的?怎么破?
非對稱加密
非對稱加密算法的特點是:私鑰加密后的密文,只要有公鑰,都能解密,但是公鑰加密后的密文,只有私鑰可以解密。私鑰只有一個人有,而公鑰可以發給所有人

這樣就可以保證 A/B 向服務器端方向發送的消息是安全的。似乎我們通過非對稱加密算法解決了密鑰的協商的問題?但是公鑰怎么拿?使用非對稱加密算法,那么如何讓 A、B 客戶端安全地持有公鑰?那么我們逐步思考,有兩種我們能想到的方案:
1. 服務器端將公鑰發送給每一個客戶端
2. 服務器端將公鑰放到一個遠程服務器,客戶端可以請求到
方案一似乎不可行,因為,傳輸過程又是不安全的,公鑰可能會被調包

引入第三方機構
到上面這一步,最關鍵的問題是,客戶端如何知道給我公鑰的是黃蓉還是小龍女?只能找本人去證實?或者有一個第三者來幫你證實,并且第三者是絕對公正的。所以,引入一個可信任的第三者是一個好的方案。
服務端把需要傳遞給客戶端的公鑰,通過第三方機構提供的私鑰對公鑰內容進行加密后,再傳遞給客戶端? 通過第三方機構私鑰對服務端公鑰加密以后的內容,就是一個簡陋版本的“數字證書”。這個證書中包含【服務器公鑰】。


客戶端拿到這個證書以后,因為證書是第三方機構使用私鑰加密的。客戶端必須要有第三方機構提供的公鑰才能解密證書。這塊又涉及到第三方機構的公鑰怎么傳輸?(假設是先內置在系統中)以及還有一個問題,第三方機構頒發的證書是面向所有用戶,不會只針對一家發放。如果不法分子也去申請一個證書呢?
如果不法分子也拿到證書?
如果不法分子也申請了證書,那它可以對證書進行調包??蛻舳嗽谶@種情況下是無法分辨出收到的是你的證書,還是中間人的。因為不論是中間人的、還是你的證書都能使用第三方機構的公鑰進行解密。


驗證證書的有效性
事情發展到現在,問題演變成了,客戶端如何識別證書的真偽?在現實生活中,要驗證一個東西的真偽,絕大部分都是基于編號去驗證(比如大學畢業證書,比如買的數碼產品是否是山寨)所以在這里,解決方案也是一樣,如果給這個數字證書添加一個證書編號?是不是就能達到目的呢?證書上寫了如何根據證書的內容生成證書編號??蛻舳四玫阶C書后根據證書上的方法自己生成一個證書編號,如果生成的證書編號與證書上的證書編號相同,那么說明這個證書是真實的。 這塊有點類似于 md5 的驗證,我們下載一個軟件包,都會提供一個 md5 的值,我們可以拿到這個軟件包以后通過一個第三方軟件去生成一個 md5 值去做比較,是不是一樣如果一樣表示這個軟件包沒被篡改過。

對服務端的數據進行 MD5 算法得到一個MD5 的值,生成證書編號,使用第三方機構的私鑰對這個證書編號進行加密,并且會在證書中添加證書編號的生成算法。
瀏覽器內置的 CA 公鑰可以解密服務端 CA 私鑰加密的證書,通過瀏覽器內置的 CA 證書的證書編號算法對服務端返回的證書編號進行驗簽。

第三方機構的公鑰證書存哪里?
瀏覽器和操作系統都會維護一個權威的第三方機構(CA)列表(包括他們的公鑰)因為客戶端接收到的證書中會有頒發機構,客戶端就根據這個頒發機構的值在本地找到對應的公鑰
Https 原理分析
HTTPS 證書的申請過程
1. 服務器上生成 CSR 文件(證書申請文件,內容包括證書公鑰、使用的 Hash 簽名算法、申請的域名、公司名稱、職位等信息)

2. 把 CSR 文件和其他可能的證件上傳到 CA 認證機構,CA 機構收到證書申請之后,使用申請中的 Hash 算法,對部分內容進行摘要,然后使用 CA 機構自己的私鑰對這段摘要信息進行簽名(相當于證書的唯一編號)
3. 然后 CA 機構把簽名過的證書通過郵件形式發送到申請者手中。
4. 申請者收到證書之后部署到自己的 web 服務器中
客戶端請求交互流程
1. 客戶端發起請求(Client Hello 包)
- 三次握手,建立 TCP 連接
- 支持的協議版本(TLS/SSL)
- 客戶端生成的隨機數 client.random,后續用于生成“對話密鑰”
- 客戶端支持的加密算法
- sessionid,用于保持同一個會話( 如果客戶端與服務器費盡周折建立了一個 HTTPS 鏈接,剛建完就斷了,也太可惜 )
2. 服務端收到請求,然后響應(Server Hello)
- 確認加密通道協議版本
- 服務端生成的隨機數 server.random,后續用于生成“對話密鑰”
- 確認使用的加密算法(用于后續的握手消息進行簽名防止篡改)
- 服務器證書(CA 機構頒發給服務端的證書)
3. 客戶端收到證書進行驗證
- 驗證證書是否是上級 CA 簽發的, 在驗證證書的時候,瀏覽器會調用系統的證書管理器接口對證書路徑中的所有證書一級一級的進行驗證,只有路徑中所有的證書都是受信的,整個驗證的結果才是受信
- 服務端返回的證書中會包含證書的有效期,可以通過失效日期來驗證 證書是否過期
- 驗證證書是否被吊銷了
- 前面我們知道 CA 機構在簽發證書的時候,都會使用自己的私鑰對證書進行簽名證書里的簽名算法字段 sha256RSA 表示 CA 機構使用 sha256 對證書進行摘要,然后使用 RSA 算法對摘要進行私鑰簽名,而我們也知道 RSA 算法中,使用私鑰簽名之后,只有公鑰才能進行驗簽。
- 瀏覽器使用內置在操作系統上的 CA 機構的公鑰對服務器的證書進行驗簽。確定這個證書是不是由正規的機構頒發。驗簽之后得知 CA 機構使用 sha256 進行證書摘要,然后客戶端再使用 sha256 對證書內容進行一次摘要,如果得到的值和服務端返回的證書驗簽之后的摘要相同,表示證書沒有被修改過
- 驗證通過后,就會顯示綠色的安全字樣
- 客戶端生成隨機數,驗證通過之后,客戶端會生成一個隨機數 pre-master secret,客戶端根據之前的:Client.random + sever.random + pre-master 生成對稱密鑰然后使用證書中的公鑰進行加密,同時利用前面協商好的 HASH 算法,把握手消息取 HASH 值,然后用 隨機數加密 “握手消息+握手消息 HASH 值(簽名)” 并一起發送給服務端 ( 在這里之所以要取握手消息的 HASH 值,主要是把握手消息做一個簽名,用于驗證握手消息在傳輸過程中沒有被篡改過。 )
4. 服務端接收隨機數
- 服務端收到客戶端的加密數據以后,用自己的私鑰對密文進行解密。然后得到client.random/server.random/pre-master secret, HASH 值,并與傳過來的 HASH 值做對比確認是否一致。
- 然后用隨機密碼加密一段握手消息(握手消息+握手消息的 HASH 值 )給客戶端
5. 客戶端接收消息
- 客戶端用隨機數解密并計算握手消息的 HASH,如果與服務端發來的 HASH 一致,此時握手過程結束,
- 之 后 所 有 的 通 信 數 據 將 由 之 前 交 互 過 程 中 生 成 的 pre master secret /client.random/server.random 通過算法得出 session Key,作為后續交互過程中的對稱密鑰
https原理圖:
