深究HTTP系列
八千字長文詳細圖解:從輸入URL到瀏覽器顯示頁面到底發生了什么?HTTPS為什么安全?
文章目錄
- 深究HTTP系列
- HTTPS為什么安全?
- 前言
- 一、HTTPS是什么?
- 二、HTTPS前置知識
- 1.http與https在協議堆疊結構上的不同
- 2.加密演算法
- 資料加密模型
- 兩類密碼體制
- 對稱秘鑰密碼體制
- 公鑰密碼體制
- 數字簽名
- 數字簽名流程
- 數字簽名+秘密通信
- 缺陷
- 哈希演算法
- 哈希函式
- 使用哈希函式來進行報文鑒別
- 加密流程
- 為什么安全
- 三、HTTPS通信流程
- 層級關系
- 安全保證
- 具體程序
- TCP三次握手
- TLS4次握手
- 密鑰獲取原理
- TLS第一次握手
- TLS 第二次握手
- 數字證書和 CA 機構
- 證書簽發流程
- 證書鏈
- TLS第三次握手
- TLS 第四次握手
前言
我們每天上網都使用http協議,我們每天編程也使用http協議,Spring Cloud的微服務使用Http template實作RPC呼叫,到處都是HTTP這四個字……
作為一名天天接觸HTTP協議的程式員,不管是前端還是后端,怎能不了解HTTP協議呢?就連校招面試,HTTP協議也作為考官必點的一道開胃菜進行提問!
不管是面試還是開發,學好http協議都是必要的~
上期我詳細講解了HTTP協議的流程,這期我們來聊下一個話題,那就是HTTPs協議,為什么HTTPS協議能保證通訊的安全,他與HTTP協議的不同在哪里?這其中到底發生了什么呢,泡杯咖啡,聽我給你講~,
一、HTTPS是什么?
我們先看看百度百科怎么講的,
HTTPS (全稱:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全為目標的 HTTP 通道,在HTTP的基礎上通過傳輸加密和身份認證保證了傳輸程序的安全性 [1] ,HTTPS 在HTTP 的基礎下加入SSL,HTTPS 的安全基礎是 SSL,因此加密的詳細內容就需要 SSL, HTTPS 存在不同于 HTTP 的默認埠及一個加密/身份驗證層(在 HTTP與 TCP 之間),這個系統提供了身份驗證與加密通訊方法,它被廣泛用于萬維網上安全敏感的通訊,例如交易支付等方面 [2] ,
這里有很多名詞,比如傳輸加密、身份認證、SSL,很顯然,SSL被用來實作HTTPS的傳輸加密與身份認證,而這兩個就保證了資訊傳輸程序的安全性,
二、HTTPS前置知識
首先是前傳,HTTP的知識要了解,
八千字長文詳細圖解:從輸入URL到瀏覽器顯示頁面到底發生了什么?
1.http與https在協議堆疊結構上的不同
下圖是HTTP和https在協議堆疊結構上的不同,為了兼容http協議,https協議在進行tcp鏈接通訊的時候,引入了SSL(也叫TLS)協議,在TCP握手的時候,通過SSL協議的規范進行了一些報文交換,進而讓雙方的通訊能夠保證安全,到底是怎樣的操作,讓他幾個報文交換就能保證通訊安全呢?首先我們需要一些密碼學的知識,

SSL(Secure Socket Layer,安全套接字層):1994年為 Netscape 所研發,SSL 協議位于 TCP/IP 協議與各種應用層協議之間,為資料通訊提供安全支持,
TLS(Transport Layer Security,傳輸層安全):其前身是 SSL,它最初的幾個版本(SSL 1.0、SSL 2.0、SSL 3.0)由網景公司開發,1999年從 3.1 開始被 IETF 標準化并改名,發展至今已經有 TLS 1.0、TLS 1.1、TLS 1.2 三個版本,SSL3.0和TLS1.0由于存在安全漏洞,已經很少被使用到,TLS 1.3 改動會比較大,目前還在草案階段,目前使用最廣泛的是TLS 1.1、TLS 1.2,
2.加密演算法
什么樣的資訊傳輸才叫安全?我們可以拆分為四個目標,
- 保密性:傳輸的資訊不能被截獲者破譯,保證只有接收者可以看懂,
- 端點鑒別:確定接收者是可靠的,而不是黑客作為中間人來偷梁換柱當接收者,
- 資訊完整:傳輸的資訊得是完整的,不能發送程序中被人刪改,必須得完璧歸趙,
- 運行安全:服務雙方必須可靠,要不然黑客不獲取資訊,直接攻擊服務器,服務器壞掉了,何談加密傳輸呢?
為了使我們的資料安全送達對方手中,我們需要保證資料的安全,如何保證安全呢?我們可以使用一些加密手段,對資料進行編碼、加密,讓資料變成別人看不懂的亂碼,但是接收方卻知道解密的手段,這樣第三者獲取不到我們的資料,只有對方才能進行解密,獲取資料,
如何進行資料加密?我們需要了解一下基本的資料加密模型,
資料加密模型
明文
X
X
X:我們要發送的資料
密文
Y
Y
Y:經過加密的資料
加密秘鑰
K
K
K:位元串,通過秘鑰,明文可以被加密為密文,
解密秘鑰
K
K
K:位元串,通過秘鑰,密文可以被解密為明文,
加密和解密秘鑰可以一樣,也可以不一樣,取決于加密演算法的不同,
在這里,加密和解密秘鑰都是K,表示加密解密秘鑰一樣,
加密行為:
Y
=
E
k
(
X
)
Y=E_{k}{(X)}
Y=Ek?(X)
E是Encrypt,即加密的英文縮寫,通過這個表示,我們很容易就明白,X通過加密演算法E、秘鑰K,加密得到密文Y,這個程序也可以叫編碼,
解密行為:
D
k
(
Y
)
=
D
k
(
E
k
(
X
)
)
=
X
D_{k}(Y)=D_{k}(E_{k}(X))=X
Dk?(Y)=Dk?(Ek?(X))=X
D是Decrypt,即解密的英文縮寫,通過這個表示,很容易看出,Y通過秘鑰、解密演算法進行解密,就可以還原出X來,解密相當于加密的一種逆運算,這個程序也可以叫解碼,這樣的話,就可以達成較為安全的通訊了,
除了秘鑰解密,有沒有其他辦法呢?有,我們可以窮舉秘鑰或者通過復雜的數學技巧來破解密文,但是前者需要龐大到不可能實作的算力,后者需要天才的數學天賦,這樣破解的難度就變的極大,因此就達到了我們加密的目的,但是如果中間人截獲了秘鑰,那他不僅可以偽裝發送者,還可以偽裝接收者,神不知鬼不覺的發動攻擊,獲取機密資訊,
理解了基本加密的思路,讓我們再來了解一下兩類密碼體制,
兩類密碼體制
對稱秘鑰密碼體制
所謂對稱密鑰密碼體制,即加密密鑰與解密密鑰是使用相同的密碼體制,如圖所示,通信的雙方使用的就是對稱密鑰,剛才我們講解的加密模型,就是對稱秘鑰密碼體制,

使用對稱秘鑰密碼體制的演算法,雙方就可以憑借秘鑰(相同的)進行加密和解碼啦,比如經典的DES加密演算法,就可以進行加密和解密運算,
資料加密標準 DES(Data Encryption Standard)
DES全稱為Data Encryption Standard,即資料加密標準,是一種使用密鑰加密的塊演算法,1977年被美國聯邦政府的國家標準局確定為聯邦資料處理標準(FIPS),并授權在非密級政府通信中使用,隨后該演算法在國際上廣泛流傳開來,需要注意的是,在某些文獻中,作為演算法的DES稱為資料加密演算法(Data Encryption Algorithm,DEA),已與作為標準的DES區分開來,
通常,我們不需要自己發明演算法,也不需要深究原理,這由密碼學家和數學家負責,但是我們需要了解加密演算法和加密的基本原理,以備不時之需,比如和第三方系統對接介面,又比如面試官讓你聊聊常用的加密演算法等場景,必須給他說道說道,
公鑰密碼體制
所謂公鑰密碼體制,即加密密鑰與解密密鑰不同的密碼體制,
公鑰密碼體制的加密模型,可以這樣表示:
加密秘鑰Public Key:向公眾公開,簡稱PK
解密秘鑰Secret Key:自己保留,簡稱SK
加密演算法E,解密演算法D也是向公眾公開的,
下面加密開始
- 生成秘鑰對
接收者B使用秘鑰對產生器,可以產生一對秘鑰:PK與SK,SK給接收者保管,而發送者A需要擁有接收者B的PK(公開的), - 加密密文
發送者A用接收者B給你的PK進行密文加密,然后發送
Y = E P K B ( X ) Y=E_{PK_{B}}{(X)} Y=EPKB??(X)
接收者B使用自己的SK進行解密,恢復出明文
X = D S K B ( Y ) = D S K B ( E P K B ( Y ) ) X=D_{SK_{B}}(Y)=D_{SK_{B}}(E_{PK_{B}}(Y)) X=DSKB??(Y)=DSKB??(EPKB??(Y))
這樣就完成了一次秘密通信,除非秘鑰SK泄露,否則這樣的交流很難被破解,
PK和SK的加密解密可以視為一種逆運算,雖然例子是公鑰加密私鑰解密,但是私鑰加密也可以用公鑰解密,
但是公鑰加密后不能用公鑰解密,必須用私鑰解密,這就保證了資料的安全性,
我們可以看到,這一對秘鑰,只能讓A->B進行多對一單向通訊,不能雙向一對一通訊,、
A可以是多個人,因為公鑰是公開的,但是B只有一個,因為私鑰是保密的,
當然,我們可以讓他們雙向通訊,只要A也生成一對秘鑰,然后依照上述流程再走一遍,就可以實作雙向的通訊了,
缺陷:比起對稱公鑰體系,這種體系更安全,只能獲取一方的秘鑰單向通訊,但是加密解密計算開銷較大,在某些場景下,并不適合使用,
除此之外,如果入侵者代理B發布了自己的公鑰,則A使用入侵者的公鑰進行加密,入侵者使用自己的私鑰解密,獲得明文,就可以實作中間人攻擊了,僅靠A和B兩方并不能保證絕對的安全,我們需要一個公正方來證明B的真實性,B首先需要向CA申請證書,并攜帶證書進行通信,證明自己合法性,公證方稱為CA,此時就可以保證通信安全了,
數字簽名
在現實當中,為了證明合同的真實性,我們使用蓋章的方法來保證合同是真實的,在數字世界當中,如何保證在網路中資料的真實性呢?我們需要使用一種數字簽名,來保證資料的真實性,實作報文鑒別,
數字簽名可以達成三個目標:
- 接收者能夠核實發送者對報文的簽名,(報文鑒別)
- 接收者能確定資料沒有被篡改過,(報文完整性)
- 發送者時候不能抵賴對報文的簽名,(不可否認)
如何實作數字簽名?方法有很多種,使用公鑰密碼體系就可以做到,
數字簽名流程
A想發送明文X,并對X進行數字簽名,要進行簽名,需要使用A的私鑰進行加密,
X
簽
名
=
E
S
K
A
(
X
)
X_{簽名}=E_{SK_{A}}(X)
X簽名?=ESKA??(X)
然后報文發送到接收者B手中,B使用A的公鑰進行解密,
X
=
D
P
K
A
(
X
簽
名
)
X=D_{PK_{A}}(X_{簽名})
X=DPKA??(X簽名?)
由于私鑰不會被A以外的人知道,因此,我們可以核實簽名,
由于私鑰不會被A以外的人知道,因此,除了A以外的人不可能有機會篡改報文,
由于私鑰不會被A以外的人知道,但是PKA可以公布,因此可以邀請第三者進行公證,A不可抵賴,
當然,A不能是黑客,否則這就是中間人攻擊,要解決這個問題,需要引入CA機構,對A頒發一個證書,證明A不是黑客,是合法的,然后A攜帶證書資訊發送到B,B就可以通過證書(CA機構的背書)明白,A是合法的,
數字簽名+秘密通信
如果在數字簽名基礎上還想要進行秘密通訊,很簡單,只需使用公鑰密碼體制的加密方法,再給簽名套上一層秘密通訊的加密解密(公鑰體系)流程,就可以秘密通訊了,
缺陷
使用非對稱加密演算法,是非常消耗計算機性能的,若明文X長度非常長,那么一次加密就要耗費很多的CPU時間,這在某些情況下是不可接受的,必須尋找其他的報文鑒別方法,
哈希演算法
使用哈希演算法,可以實作高效的報文鑒別,
哈希函式
哈希演算法,使用密碼散列函式來對資料進行編碼,該函式具有如下特點:
- 輸入長度可以不固定,但是輸出長度是固定的,而且很短, 輸出長度被稱為散列值,
- 不同的散列值肯定對應不同的輸入,但是不同的輸入可能得出相同的散列值,(幾率很小)
- 不可能從輸出計算出輸入,通常認為這在理論上是不可能的,
因此,只要我們發送的資料中,包含哈希輸入與散列值,就可以基本保證哈希輸入與散列值的一一對應性,程序如下:
X : 明 文 , H : 散 列 函 數 X:明文,H:散列函式 X:明文,H:散列函數,可以發送
M e s s a g e = ( X , H ( X ) ) Message=(X,H(X)) Message=(X,H(X))
對于每個Message,可以確保X與H(X)是對應的,
對于這種東西,一般只能采用暴力法破解,如暴力破解、彩虹表、字典攻擊、詞表重整攻擊、概率背景關系無關文法,但是只要多次加鹽加密,這些方法都很難破解哈希演算法加密,
使用哈希函式來進行報文鑒別
為了確保沒有中間人通過偽造X、使用相同的H計算出H(X)來偽造Message資訊,需要對H(X)進行加密,由于H(X)長度恒定且不長,這時候,加密的效率就是可以保證的了!
加密流程
設秘鑰為K,這里使用對稱加密演算法,K的安全性問題可以另外解決(比如使用公鑰體系加密方法),此時假設是可以保證的,
- 發送者構造報文 M e s s a g e = ( X , E k ( H ( X ) ) ) Message=(X,E_{k}(H(X))) Message=(X,Ek?(H(X))),加密過的散列值被稱為報文鑒別碼MAC,
- 發送報文,經過互聯網傳輸,
- 接收者分離報文X,加密過的散列值 E k ( H ( X ) ) E_{k}(H(X)) Ek?(H(X))
- 使用秘鑰解密, H ( X ) = D k ( E k ( H ( X ) ) ) H(X)=D_k(E_{k}(H(X))) H(X)=Dk?(Ek?(H(X)))
- 對X使用散列演算法,得到H(X),與解密的值進行比較,相同則鑒別成功,
為什么安全
只要保證了入侵者不知道秘鑰K,就沒有辦法偽造出報文鑒別碼MAC,接收者解密后就無法得到正確的散列值,因此比較失敗,報文鑒別成功,
三、HTTPS通信流程
層級關系
HTTPS的通信流程,就是在HTTP基礎上,加上了TLS層進行安全認證,
層級關系可以參考下圖,TLS可以說是運輸層協議,但是其實在應用層的程式也會集成一部分TLS的內容用于介面呼叫和通訊,

HTTP服務器與TLS之間有一個TLS 套接字通道,用來傳遞資料給TLS層,TLS層對資料進行包裝加密等操作,并負責連接TCP進行報文交換(TLS層與目標埠(443)也有一個套接字通道,該通道為TCP真正交流埠,就像HTTP的埠80一樣),
安全保證
TLS協議提供以下三個安全保障,利用之前我們學習的前置知識,很容易理解這幾個保證到底是怎么實作的,
- 資訊加密:HTTP 互動資訊是被加密的,第三方就無法被竊取;
- 校驗機制:校驗資訊傳輸程序中是否有被第三方篡改過,如果被篡改過,則會有警告提示;
- 身份證書:保證Server端的真實性;
具體程序
這里程序參考了幾幅圖拿下 HTTPS,感謝作者的抓包和解讀,
TCP三次握手
TLS是基于TCP協議的,進行TLS之前,首先進行日常的三次握手協議,這里內容參考上一篇文章,
TLS4次握手

其中每一個「框」都是一個記錄(record),記錄是 TLS 收發資料的基本單位,類似于 TCP 里的 segment,
多個記錄可以組合成一個 TCP 包發送,所以通常經過「四個訊息」就可以完成 TLS 握手,也就是需要 2個 RTT 的時延,然后就可以在安全的通信環境里發送 HTTP 報文,實作 HTTPS 協議,

密鑰獲取原理
首先,為了安全,我們需要密鑰加密,兼顧效率和安全,TLS使用公鑰體系與對稱密鑰體系混合的方法進行密鑰的獲取,首先使用公鑰體系的方法,非對稱加密獲取一個對稱的密鑰,之后雙方使用對稱密鑰進行交流,這樣保證了對稱密鑰不會被入侵者利用,也保證加密解密效率足夠高,
這個對稱密鑰,在握手中稱為會話密鑰,
TLS第一次握手
客戶端首先會發一個「Client Hello」訊息,和服務器打招呼,具體內容如下,

訊息里面有客戶端使用的 TLS 版本號、支持的密碼套件串列,以及生成的亂數(Client Random)**,這個亂數會被服務端保留,它是生成對稱加密密鑰的材料之一,
TLS 第二次握手
當服務端收到客戶端的「Client Hello」訊息后,會確認 TLS 版本號是否支持,和從密碼套件串列中選擇一個密碼套件,以及生成亂數(Server Random),接著,回傳「Server Hello」訊息,訊息里面有服務器確認的 TLS 版本號,也給出了亂數(Server Random),然后從客戶端的密碼套件串列選擇了一個合適的密碼套件,

可以看到,服務端選擇的密碼套件是 “Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256”,這個密碼套件看起來真讓人頭暈,好一大串,但是其實它是有固定格式和規范的,基本的形式是「密鑰交換演算法 + 簽名演算法 + 對稱加密演算法 + 摘要演算法」, 一般 WITH 單詞前面有兩個單詞,第一個單詞是約定密鑰交換的演算法,第二個單詞是約定證書的驗證演算法,比如剛才的密碼套件的意思就是:
- 由于 WITH 單詞只有一個 RSA,則說明握手時密鑰交換演算法和簽名演算法都是使用 RSA;
- 握手后的通信使用 AES 對稱演算法,密鑰長度 128 位,分組模式是 GCM;
- 摘要演算法 SHA256 用于訊息認證和產生亂數;
就前面這兩個客戶端和服務端相互「打招呼」的程序,客戶端和服務端就已確認了 TLS 版本和使用的密碼套件,而且你可能發現客戶端和服務端都會各自生成一個亂數,并且還會把亂數傳遞給對方,那這個亂數有啥用呢?其實這兩個亂數是后續作為生成「會話密鑰」的條件,所謂的會話密鑰就是資料傳輸時,所使用的對稱加密密鑰,然后,服務端為了證明自己的身份,會發送「Server Certificate」給客戶端,這個訊息里含有數字證書,
這證書里,就含有我們需要的公鑰,
數字證書和 CA 機構
一個數字證書通常包含了:
- 公鑰;
- 持有者資訊;
- 證書認證機構(CA)的資訊;
- CA 對這份檔案的數字簽名及使用的演算法;
- 證書有效期;
- 還有一些其他額外資訊;
數字證書的作用,是用來認證公鑰持有者的身份,以防止第三方進行冒充,說簡單些,為了讓服務端的公鑰被大家信任,服務端的證書都是由 CA (Certificate Authority,證書認證機構)簽名的,CA 就是網路世界里的公安局、公證中心,具有極高的可信度,所以由它來給各個公鑰簽名,信任的一方簽發的證書,那必然證書也是被信任的,之所以要簽名,是因為簽名的作用可以避免中間人在獲取證書時對證書內容的篡改,
證書簽發流程
如圖
- 先是對數字證書的相關資訊來一個hash運算,得到散列值,
- 然后CA自己的私鑰加密散列值,這個操作我們之前講過,是CA進行了數字簽名,
- 然后把簽名附加在檔案證書上,這樣就形成了數字證書,
客戶端需要驗證數字證書,確保CA機構的合格性,這是驗證的常規操作,我們之前也講了,
- 首先客戶端會使用同樣的 Hash 演算法獲取該證書的 Hash 值 H1;
- 通常瀏覽器和作業系統中集成了 CA 的公鑰資訊,瀏覽器收到證書后可以使用 CA 的公鑰解密Certificate Signature 內容,得到一個 Hash 值 H2 ;
- 最后比較 H1 和 H2,如果值相同,則為可信賴的證書,否則則認為證書不可信,
證書鏈
如圖,我們申請的證書,一般是中間證書簽發的,比如百度,但是瀏覽器通常只信任根證書,因此瀏覽器會發起申請,驗證百度證書的可信性,然后繼續重復直到根證書,
- 客戶端收到 baidu.com 的證書后,發現這個證書的簽發者不是根證書,就無法根據本地已有的根證書中的公鑰去驗證 baidu.com 證書是否可信,于是,客戶端根據 baidu.com 證書中的簽發者,找到該證書的頒發機構是 “GlobalSign Organization Validation CA - SHA256 - G2”,然后向 CA 請求該中間證書,
- 請求到證書后發現 “GlobalSign Organization Validation CA - SHA256 - G2” 證書是由 “GlobalSign Root CA” 簽發的,由于 “GlobalSign Root CA” 沒有再上級簽發機構,說明它是根證書,也就是自簽證書,應用軟體會檢查此證書有否已預載于根證書清單上,如果有,則可以利用根證書中的公鑰去驗證 “GlobalSign Organization Validation CA - SHA256 - G2” 證書,如果發現驗證通過,就認為該中間證書是可信的,
- “GlobalSign Organization Validation CA - SHA256 - G2” 證書被信任后,可以使用 “GlobalSign Organization Validation CA - SHA256 - G2” 證書中的公鑰去驗證 baidu.com 證書的可信性,如果驗證通過,就可以信任 baidu.com 證書,
根證書一般內置于作業系統或者瀏覽器中,我們也可以手動添加證書,
通過這種鏈條一樣的方式,最終瀏覽器就可以成功進行證書的認證了,
證書報文:

隨后,服務端發了「Server Hello Done」訊息,目的是告訴客戶端,我已經把該給你的東西都給你了,本次打招呼完畢,

TLS第三次握手
客戶端驗證完證書后,認為可信則繼續往下走,接著,客戶端就會生成一個新的亂數 (pre-master),用服務器的 RSA 公鑰加密該亂數,通過「Change Cipher Key Exchange」訊息傳給服務端,

服務端收到后,用 RSA 私鑰解密,得到客戶端發來的亂數 (pre-master),至此,客戶端和服務端雙方都共享了三個亂數,分別是 Client Random、Server Random、pre-master,于是,雙方根據已經得到的三個亂數,生成會話密鑰(Master Secret),它是對稱密鑰,用于對后續的 HTTP 請求/回應的資料加解密,生成完會話密鑰后,然后客戶端發一個「Change Cipher Spec」,告訴服務端開始使用加密方式發送訊息,

然后,客戶端再發一個「Encrypted Handshake Message(Finishd)」訊息,把之前所有發送的資料做個摘要,再用會話密鑰(master secret)加密一下,讓服務器做個驗證,驗證加密通信是否可用和之前握手資訊是否有被中途篡改過,

可以發現,「Change Cipher Spec」之前傳輸的 TLS 握手資料都是明文,之后都是對稱密鑰加密的密文,
TLS 第四次握手
服務器也是同樣的操作,發「Change Cipher Spec」和「Encrypted Handshake Message」訊息,如果雙方都驗證加密和解密沒問題,那么握手正式完成,
最后,就用「會話密鑰」加解密 HTTP 請求和回應了,
可以看到,通過在CA證書里集成公鑰,我們解決了中間人攻擊的問題,
而私鑰我們默認服務器應該安全的保管,責任在接收方,因此是安全的,
若入侵者破解了私鑰,過去被第三方截獲的所有 TLS 通訊密文都會被破解,因此RSA也不是百分百安全的,為了避免這個問題,可以使用 安全的DH 密鑰協商演算法、效率更好的ECDHE 密鑰協商演算法(現在一般都用這個),但是在這里就不展開講了,可以自己百度看看,
這里的程序比較繁雜,可以搭配下面的流程圖,配合抓包內容進行學習,

八千字長文詳細圖解:從輸入URL到瀏覽器顯示頁面到底發生了什么?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/276978.html
標籤:其他
下一篇:步道樂跑


