當前位置:
首頁 > 最新 > HTTPS實戰之單向驗證和雙向驗證

HTTPS實戰之單向驗證和雙向驗證

(全文太長,太懶不想看,-_-b 那就直接拉到底部看總結 )

前面的文章中,提到了,https是在TCP協議與http之間加了一個控制安全傳輸的SSL協議,也就是說,直接運行在TCP之上的HTTP是普通的HTTP,運行在SSL/TLS上的HTTP則是HTTPS。這幾個協議在計算機網路的OSI七層模型中的位置如下表所示:

客戶端執行https請求時,需要由TCP協議建立和釋放連接。這就涉及TCP協議的三次握手和四次揮手。

注意:我們可能會經常看到「HTTP的三次握手」這個說法,其實這種說法不準確,HTTP是沒有什麼三次握手的,這個其實指的就是TCP的三次握手。

一、TCP的三次握手(不想了解,可跳過)

TCP通過三次握手,建立連接

第一次:客戶端發送一個唯一的數據包(SYNJ)給伺服器,請求建立連接

第二次:伺服器收到客戶端的請求後,生成一個SYN J的回應包(ack J+1)和一個新的數據包(SYN K),發給客戶端

第三次:客戶端收到伺服器返回的兩個包後,針對伺服器的SYN K包生成一個回應包(ack K+1),並發送給伺服器。至此,完成3步握手。這個過程,類似我們在信號不好的時候打電話的過程:

「喂,能聽到我說話嗎」

「我能聽到,你能聽到我嗎」

「能聽到」

...

注意,這裡「能聽到」包含了「聽到」「聽懂」的兩層意思。想像一下,你用中文,對方給你回了一個你聽不懂的俄文,這個通話也就沒有必要進行下去了。

二、TCP的四次揮手(不想了解,可跳過)

TCP協議是一個全雙工協議(可以同時進行收發),通過四次揮手關閉連接。

簡單理解:

第一步:客戶端發送FIN(M)報文給伺服器,告訴對方,「我的數據發完了」。

第二步:伺服器收到FIN(M)報文後,回給客戶端一個ack(M+1)報文,告訴客戶端,「好,我知道了」。

第三步:伺服器發一個FIN(N)報文給客戶端,告訴對方,「我的數據也發完了」。

第四步:客戶端回應ack(N+1),告訴伺服器,「好,我知道了」,至此,連接結束。

這個過程類似兩個人打完電話的結束過程。

A:我說完了

B:哦

B想了一下,也沒什麼要說的

B:我也說完了

A:好

通話結束,雙方掛電話

三、HTTPS單向驗證

TCP連接建立好後,對於HTTP而言,伺服器就可以發數據給客戶端。但是對於HTTPS,它還要運行SSL/TLS協議,SSL/TLS協議分兩層,第一層是記錄協議,主要用於傳輸數據的加密壓縮;第二層是握手協議,它建立在第一層協議之上,主要用於數據傳輸前的雙方身份認證、協商加密演算法、交換密鑰。

HTTPS驗證過程就是SSL握手協議的交互過程。「HTTPS驗證」這個說法其實不準確的,應該是「SSL驗證」,這兩種說法網上都能看到。

我們先從簡單點的單向驗證開始解釋:

一步:客戶端發起ClientHello

客戶端向指定域名的伺服器發起https請求,請求內容包括:

1)客戶端支持的SSL/TLS協議版本列表

2)支持的對稱加密演算法列表

3)客戶端生成的隨機數A

二步:服務端回應SeverHello

伺服器收到請求後,回應客戶端,回應的內容主要有:

1)SSL/TLS版本。伺服器會在客戶端支持的協議和伺服器自己支持的協議中,選擇雙方都支持的SSL/TLS的最高版本,作為雙方使用的SSL/TLS版本。如果客戶端的SSL/TLS版本伺服器都不支持,則不允許訪問

2)與1類似,選擇雙方都支持的最安全的加密演算法。

3)從伺服器密鑰庫中取出的證書

4)伺服器端生成的隨機數B

第三步:客戶端回應

客戶端收到後,檢查證書是否合法,主要檢查下面4點:

1、檢查證書是否過期

2、檢查證書是否已經被吊銷

有CRL和OCSP兩種檢查方法。CRL即證書吊銷列表,證書的屬性裡面會有一個CRL分發點屬性,如下圖所示(CSDN的證書),這個屬性會包含了一個url地址,證書的簽發機構會將被吊銷的證書列表展現在這個url地址中;OCSP是在線證書狀態檢查協議,客戶端直接向證書籤發機構發起查詢請求以確認該證書是否有效。

3、證書是否可信

客戶端會有一個信任庫,裡面保存了該客戶端信任的CA(證書籤發機構)的證書,如果收到的證書籤發機構不在信任庫中,則客戶端會提示用戶證書不可信。

若客戶端是瀏覽器,各個瀏覽器都會內置一些可信任的證書籤發機構列表,在瀏覽器的設置中可以看到。

如果不在信任表中,則瀏覽器會出現類似下面的警告頁面,提示你不安全。(當然,你可以選擇繼續訪問)

若客戶端是程序,例如Java中,需要程序配置信任庫文件,以判斷證書是否可信,如果沒設置,則默認使用jdk自帶的證書庫(jrelibsecuritycacerts,默認密碼changeit)。如果證書或簽發機構的證書不在信任庫中,則認為不安全,程序會報錯。(你可以在程序中設置信任所有證書,不過這樣並不安全)。

4、檢查收到的證書中的域名與請求的域名是否一致。

若客戶端是程序,這一項可配置不檢查。若為瀏覽器,則會出現警告,用戶也可以跳過。

證書驗證通過後,客戶端使用特定的方法又生成一個隨機數c,這個隨機數有專門的名稱「pre-master key」。接著,客戶端會用證書的公鑰對「pre-master key」加密,然後發給伺服器。

第四步,伺服器的最後回應

伺服器使用密鑰庫中的私鑰解密後,得到這個隨機數c。此時,服務端和客戶端都拿到了隨機數a、b、c,雙方通過這3個隨機數使用相同的DH密鑰交換演算法計算得到了相同的對稱加密的密鑰。這個密鑰就作為後續數據傳輸時對稱加密使用的密鑰。

伺服器回應客戶端,握手結束,可以採用對稱加密傳輸數據了。

這裡注意幾點:

1、整個驗證過程,折騰了半天,其實是為了安全地得到一個雙方約定的對稱加密密鑰,當然,過程中也涉及一些身份認證過程。既然剛開始時,客戶端已經拿到了證書,裡面包含了非對稱加密的公鑰,為什麼不直接使用非對稱加密方案呢,這是因為非對稱加密計算量大、比較耗時,而對稱加密耗時少。

2、對稱加密的密鑰只在這次連接中斷前有效,從而保證數據傳輸安全。

3、為什麼要用到3個隨機數,1個不行嗎?這是因為客戶端和服務端都不能保證自己的隨機數是真正隨機生成的,這樣會導致數據傳輸使用的密鑰就不是隨機的,時間長了,就很容易被破解。如果使用客戶端隨機數、服務端隨機數、pre-master key隨機數這3個組合,就能十分接近隨機。

4、什麼是信任庫和密鑰庫。信任庫前面已經說了,它是用來存放客戶端信任的CA的證書。在程序交互中,需要確保你訪問的伺服器的證書在你的信任庫裡面。密鑰庫是用來存放伺服器的私鑰和證書。

5、中間人攻擊問題。前面過程說明中,有一點,客戶端是驗證有問題的時候,是可以選擇繼續的。對瀏覽器而言,用戶可以選擇繼續訪問;對程序而言,有些系統為了處理簡單,會選擇信任所有證書,這樣就給中間人攻擊提供了漏洞。

中間人攻擊時,它想辦法攔截到客戶端與伺服器之間的通信。在客戶端向伺服器發信息時,中間人首先偽裝成客戶端,向真正的伺服器發消息,獲得真正的證書,接著偽裝成伺服器將自己的偽證書發給客戶端。伺服器向客戶端發消息時,中間人偽裝成客戶端,接收消息,然後再偽裝成伺服器向客戶端發消息。最後驗證過程完成後,客戶端的真實對稱密鑰被中間人拿到,而真正的伺服器拿到的是中間人提供的偽密鑰。後續數據傳輸過程中的數據就會被中間人竊取。

四、HTTPS雙向驗證

單向驗證過程中,客戶端會驗證自己訪問的伺服器,伺服器對來訪的客戶端身份不做任何限制。如果伺服器需要限制客戶端的身份,則可以選擇開啟服務端驗證,這就是雙向驗證。從這個過程中我們不難發現,使用單向驗證還是雙向驗證,是伺服器決定的。

一般而言,我們的伺服器都是對所有客戶端開放的,所以伺服器默認都是使用單向驗證。如果你使用的是Tomcat伺服器,在配置文件server.xml中,配置Connector節點的clientAuth屬性即可。若為true,則使用雙向驗證,若為false,則使用單向驗證。如果你的服務,只允許特定的客戶端訪問,那就需要使用雙向驗證了。

雙向驗證基本過程與單向驗證相同,不同在於:

1)第二步伺服器第一次回應客戶端的SeverHello消息中,會要求客戶端提供「客戶端的證書」

2)第三步客戶端驗證完伺服器證書後的回應內容中,會增加兩個信息:

1、客戶端的證書

2、客戶端證書驗證消息(CertificateVerifymessage):客戶端將之前所有收到的和發送的消息組合起來,並用hash演算法得到一個hash值,然後用客戶端密鑰庫私鑰對這個hash進行簽名,這個簽名就是CertificateVerify message

說明:這裡關於客戶端私鑰的使用,網上有很多文章認為:在協商對稱加密方案時,服務端先用客戶端公鑰加密伺服器選定的對稱加密方案,客戶端收到後使用私鑰解密得到。首先,對稱加密方案就那麼幾種,逐個試試就能試出來,沒必要為了這個增加一個客戶端和服務端的交互過程。而這裡關於CertificateVerify message的說法參考了維基百科關於「Transport Layer Security」一文中"Client-authenticated TLS handshake"的描述。鏈接:https://en.wikipedia.org/wiki/Transport_Layer_Security#Client-authenticated_TLS_handshake

3)伺服器收到客戶端證書後:

a)確認這個證書是否在自己的信任庫中(當然也會校驗是否過期等信息),如果驗證不通過則會拒絕連接;

b)用客戶端證書中的公鑰去驗證收到的證書驗證消息中的簽名。這一步的作用是為了確認證書確實是客戶端的。

所以,在雙向驗證中,客戶端需要用到密鑰庫,保存自己的私鑰和證書,並且證書需要提前發給伺服器,由伺服器放到它的信任庫中。

五、總結一下:

1、單向驗證中,如果是你客戶端,你需要拿到伺服器的證書,並放到你的信任庫中;如果是服務端,你要生成私鑰和證書,並將這兩個放到你的密鑰庫中,並且將證書發給所有客戶端。

2、雙向驗證中,如果你是客戶端,你要生成客戶端的私鑰和證書,將它們放到密鑰庫中,並將證書發給服務端,同時,在信任庫中導入服務端的證書。如果你是服務端,除了在密鑰庫中保存伺服器的私鑰和證書,還要在信任庫中導入客戶端的證書。

3、再次強調,使用單向驗證還是雙向驗證,是伺服器決定的。

4、https的驗證過程,不管是單向還是雙向,只有四步,網上很多關於https驗證過程的文章中,寫了來來回回七八上十步。要真是這樣,訪問一個https地址,時間全花在了交互上了。

-END-

寫得不錯,轉發分享一下吧


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 coding濤 的精彩文章:

https實戰之數字證書

TAG:coding濤 |