TLS握手協議分析與理解——某HTTPS請求流量包分析

https://xz.aliyun.com/t/1039html

 

HTTPS簡介

  • HTTPS,是一種網絡安全傳輸協議,在HTTP的基礎上利用SSL/TLS來對數據包進行加密,以提供對網絡服務器的身份認證,保護交換數據的隱私與完整性。
    • TLS(Transport Layer Security)1.0是SSL(Secure Sockets Layer)3.0的升級版,安全套接字層協議,承擔的角色都是同樣的,是HTTPS方式握手以及傳輸數據的一個協議。只是改了名字,其中的八卦,感興趣的朋友能夠本身去搜索。
  • HTTP(S)協議是在TCP/IP協議基礎上建造的。
  • TCP/IP協議的分層管理,按層次分爲:應用層、傳輸層、網絡層、數據鏈路層。(咱們常說的四層協議、四層模型就是指的這個啦)
  • 沒有通過加密層時,數據傳輸的路徑是:應用層->傳輸層->網絡層->數據鏈路層
  • 通過加密層以後,數據傳輸的路徑是:應用層->SSL/TLS層->傳輸層->網絡層->數據鏈路層
  • 每層常見的協議:
    • 應用層協議有:FTP、Telnet、SMTP、HTTP、RIP、NFS、DNS。
    • 傳輸層協議有:TCP協議、UDP協議。
    • 網絡層協議有:IP協議、ICMP協議、ARP協議、RARP協議。

HTTPS用途

  • 防竊聽:HTTPS協議對傳輸數據的內容加密,保障數據在傳輸過程的安全(加密傳播)
  • 防冒充:確認網站的真實性(身份證書)
  • 防篡改:防止內容被第三方篡改(校驗機制)

HTTPS協議安全性

  • HTTPS協議自己是安全的,而且可以保障數據傳輸安全、兩端身份真實、以及檢查數據是否被篡改。
  • 但近幾年有https相關的漏洞頻發,如心血漏洞、中間人攻擊、DROWN溺水攻擊、FREAK漏洞、降維攻擊、POODLE等(近期會將每一個漏洞原理進行分析)。不禁讓人爲https的安全性擔心,其實這個協議的邏輯通常是設計的很是安全了,即便出現問題,也會有大版本的升級(如TLS 1.0升級爲TLS 1.1)。並且頻發漏洞的並非https協議自己,而是各個開源或商業服務在具體實現https時,出現了安全問題。

https如何進行數據傳輸的?

  • 大體流程是:進行握手流程創建https鏈接(此時是明文傳輸),而後再進行真正的數據傳輸(此時使用對稱加密進行密文傳輸)
  • 首先須要瞭解TLS/SSL協議握手的過程

握手過程

  • 整個過程,如訪問www.baidu.com
    • 先進行DNS解析,再創建TCP鏈接,而後進行https握手,最後傳輸加密數據。

握手消息 動做描述 消息內容
1. Client —> ClientHello —> Server 客戶端(瀏覽器)發送一個hello消息給服務端,發起創建SSL會話的請求。並告訴服務端,本身支持哪些加密算法(Cipher Suite List)。除此以外,還須要產生一個隨機數(第一個隨機數,用於之後生成對稱密鑰),發送給服務端。 1)支持的協議版本,如TLS 1.0版<br/>2)由客戶端生成的隨機數,用於生成後面的「對稱密鑰」<br/>3)支持的加密方法,好比RSA公鑰加密<br/>4)支持的壓縮方法<br/>5)請求的域名<br/>
2. Server —> ServerHello —> Client 服務端的首次響應,會肯定加密協議版本,以及加密的算法,也會生成一個隨機數(第二個隨機數)給客戶端。 1)協議的版本<br/>2)加密的算法<br/>3)服務端生成的隨機數<br/>
3. Server —> Certificate —> Client 還會把本身的證書發送給客戶端,讓客戶端進行校驗。服務端證書中的公鑰也可被用於加密後面握手過程當中生成的對稱密鑰。 1)服務端證書<br/>證書頒發機構的名稱<br/>證書自己的數字簽名<br/>證書持有者公鑰<br/>證書籤名用到的Hash算法<br/>
4. Server --> ServerKeyExchange —> Client 指定使用哪一種密鑰協商協議。服務端能夠在ServerKeyExchange以後當即發送CertificateRequest消息,要求校驗客戶端的證書。 1)使用哪一種密鑰協商方式<br/>2)密鑰協商時客戶端須要的信息
5. Server —> ServerHelloDone —> Client 服務器發送ServerHelloDone消息,告知客戶端服務器這邊握手相關的消息發送完畢。  
6. Client —> ClientKeyExchange —> Server 消息中包含客戶端這邊的EC Diffie-Hellman算法相關參數,而後服務器和客戶端均可根據接收到的對方參數和自身參數運算出對稱密鑰。 1)密鑰協商時服務端須要的信息
7. Client —> ChangeCipherSpec —> Server ChangeCipherSpec消息,通知服務器此消息之後客戶端會以加密方式發送數據。 準備好了作加密傳輸的通知
8. Client —> Finished —> Server 客戶端計算生成對稱密鑰,而後使用該對稱密鑰加密以前全部收發握手消息的Hash值,發送給服務器,服務器將相同的會話密鑰(使用相同方法生成)解密此消息,校驗其中的Hash值。  
9. Server —> ChangeCipherSpec —> Client ChangeCipherSpec消息,通知客戶端此消息之後服務器會以加密方式發送數據。 準備好了作加密傳輸的通知
10. Server — > Finished —> Client 服務器使用對稱密鑰加密(生成方式與客戶端相同)以前所發送的全部握手消息的hash值,發送給客戶端去校驗。  
11. Application Data 真正的數據傳輸(使用對稱加密)

1. Client Hello

  • 客戶端發起TLS握手請求
    struct { ProtocolVersion client_version; Random random; SessionID session_id; CipherSuite cipher_suites<2..2^16-2>; CompressionMethod compression_methods<1..2^8-1>; select (extensions_present) { case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ClientHello; 
  • 數據包括內容:
    • ProtocolVersion/協議版本(客戶端指望支持的握手協議版本
    • Random/安全隨機數(MasterSecret生成用到,協議文檔裏面說是28個字節,可是實際抓包看到是32個字節,這裏懷疑是各個協議文檔版本不一樣,還有使用加密套件的不一樣,致使的差別,具體博主就沒有在繼續深究了,若是有朋友知道能夠留言給我)
    • SessionID/會話ID
      • 這個值是被服務端設置的,若是這個值爲空,表示客戶端與服務端沒有存活的https會話,須要與服務端進行完整的握手。
      • 若是這個值存在,則代表客戶端指望恢復上一次的https會話,這時候客戶端與服務端只須要進行快速的握手過程。(這裏咱們只會分析完整的握手過程進行學習)
    • CipherSuite/加密套件(客戶端支持的加密套件列表)
      • 若是sessionid不爲空,能夠不傳這個值,服務端能夠從上一次會話中恢復這個值。
      • 每一個加密組件(Cipher Suite)都包括了下面5類算法 TLS Cipher Suite Registry,圖中百度使用的是就是 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 這個加密套件:
        • 一、authentication (認證算法):RSA
        • 二、encryption (加密算法 ):AEAD_AES_128_GCM
        • 三、message authentication code (消息認證碼算法 簡稱MAC):SHA256
        • 四、key exchange (密鑰交換算法):ECDHE
        • 五、key derivation function (密鑰衍生算法)
    • CompressionMethod/壓縮方法
      • 加密前進行數據壓縮
      • 由於壓縮方法被攻擊,在TLS1.3協議版本上已經完全禁止壓縮了。(這裏有兩種攻擊方式BREACH、CRIME,有時間博主會來研究)
    • Extension/擴展數據(session ticket在擴展裏面,可見下圖)
  • 消息內容以下圖:

2. Server Hello

  • 服務端迴應Client Hello請求
    struct { ProtocolVersion server_version; Random random; SessionID session_id; CipherSuite cipher_suite; CompressionMethod compression_method; select (extensions_present) { case false: struct {}; case true: Extension extensions<0..2^16-1>; }; } ServerHello; 
  • 主要發送數據內容:
    • ProtocolVersion/握手協議版本
      • 服務端最高支持的握手協議版本,TLS/SSL協議都是向下兼容的。
    • Random/隨機數
      • 服務端生成32字節安全隨機數(MasterSecret生成會用到)
    • SessionID/會話ID
      • 若是客戶端hello有發送session id,服務端從內存中查找,並嘗試恢復以前的會話狀態。
        • 恢復成功,服務端返回一樣的session id。
        • 恢復不成功,服務端此字段返回空。
    • CipherSuite/加密組件
      • 服務端從客戶端hello的cipher suite列表中選擇一個加密套件,若是是恢復上一次的會話,則從會話狀態中恢復上一次相同的加密套件。
    • CompressionMethod/壓縮方法
      • 服務端從客戶端hello的compression_methods列表中選擇一個壓縮方法,若是是恢復上一次的會話,則從會話狀態中恢復上一次相同的壓縮方法。
    • Extension/擴展(以下圖)
  • 消息以下面所示:

3. Server Certificate

  • 服務端發送的是一個證書鏈,可能包含多個證書
    • 第一個證書爲網站的證書。
    • 第二個證書爲頒發證書給網站的機構的證書。
    • 在這個例子中第三個證書是CA機構的根證書,能夠忽略不用發送,由於這個CA的根證書是CA本身給本身頒發的。
      這裏構成了一個證書信任鏈,也就是 GlobalSign Root CA信任GlobalSign Organization Validation CA,而他又信任baidu.com的證書。
      以下圖所示:

  • CA證書的類型有3類:DV ( domain validation),OV ( organization validation),EV ( extended validation),證書申請難度從前日後遞增。
  • 證書中都包含了哪些信息?
    ```html
  • 證書版本號(Version)
  • 證書序列號(Serial Number)
  • 簽名算法標識符(Signature Algorithm)
    簽名算法標識用來指定由CA簽發證書時所使用的"簽名算法"。算法標識符用來指定CA簽發證書時所使用的:
    1) 公開密鑰算法
    2) hash算法
    example: sha256WithRSAEncryption
    須向國際知名標準組織(如ISO)註冊
  • 簽發機構名(Issuer)
  • 有效期(Validity):指定證書的有效期
  • 證書用戶名(Subject)
  • 證書持有者公開密鑰信息(Subject Public Key Info)
    證書持有者公開密鑰信息域包含兩個重要信息:
    1) 證書持有者的公開密鑰的值
    2) 公開密鑰使用的算法標識符。此標識符包含公開密鑰算法和hash算法。
  • 擴展項(extension)
  • 簽發者惟一標識符(Issuer Unique Identifier)
  • 證書持有者惟一標識符(Subject Unique Identifier)
  • 簽名算法(Signature Algorithm)
  • 簽名值(Issuer's Signature)
    ```
  • 以下圖所示

如何校驗服務端證書呢?

  • 簽名的生成:CA先將證書信息生成hash摘要,而後再用CA機構的私鑰進行加密。
  • 簽名的校驗:使用CA機構的公鑰進行解密簽名,獲得hash摘要A,再計算證書信息的hash摘要B。比對是否一致。
    #### 詳細解釋服務端的證書是怎麼生成的?
  • 服務端的證書是由CA (Certificate Authority,證書認證中心)頒發的。他是一個負責發放和管理數字證書的第三方權威機構,它負責管理PKI(Public Key Infrastructure,公開密鑰基礎設施)結構下的全部用戶(包括各類應用程序)的證書,把用戶的公鑰和用戶的其餘信息捆綁在一塊兒,在網上驗證用戶的身份。
  • 通常狀況下網站方向CA申請一個證書。CA會給網站方生成一對非對稱加密的公鑰私鑰,公鑰會作到證書裏面,私鑰則會給到網站方。
  • CA會先作一個「數字簽名」(生成過程:明文 --> hash運算 --> 摘要 --> 私鑰加密 --> 數字簽名)
    • 就是將網站方的信息網站方的公鑰簽名算法等信息(就是Wireshark Packet 20中的數據,除了「簽名值」),計算一個hash值(圖中hash算法是SHA256),而後CA再用本身私鑰作加密(圖中公開密鑰算法是RSA),最後的這個密文就是「數字簽名」(也就是咱們在圖中看到「encrypted」簽名值)。
  • CA最後將「網站方信息」、「網站方公鑰」、「簽名算法」、「簽名值」都作到證書裏面(就是Wireshark Packet 20中的咱們看到那些數據),證書就作好了,CA會把「證書」和「網站方的私鑰」給到網站方。

CA怎麼驗證證書是否是本身頒發的呢?以及作證書內容校驗?

  • 首先瀏覽器(校驗網站的證書)或操做系統(校驗應用的證書),會在操做系統存儲的系統信任的根證書裏面去查找「證書頒發機構」是不是信任的。以下圖系統根證書:

* 瀏覽器一般也會內置大多數主流權威CA的根證書。
* 若是查找不到對應的可信CA,則判斷這個證書是僞造的,不可信的。(瀏覽器則會提醒該證書不是可信任機構頒發的,並詢問是否要繼續訪問)
  • 若是找到對應的CA機構,則取出CA機構證書裏面的公鑰信息,將網站方證書中的簽名值(也就是數字簽名)作解密,獲得網站證書信息的hash摘要A。
  • 而後將網站證書中的信息,作hash獲得摘要B,比對摘要A和摘要B是否一致。若是不一致,說明網站證書中的信息被修改了。(瀏覽器則會提醒該證書不是可信任機構頒發的,並詢問是否要繼續訪問)
  • 若是摘要hash一致,則說明證書中的信息未被修改,這時瀏覽器會比對您如今正在訪問的網站與證書中網站信息是否一致,好比域名是否一致、證書是否在有效期內等。(若是出現問題,瀏覽器將會提醒你,並詢問是否要繼續訪問)
  • 另外大部分瀏覽器也會在線校驗證書,是否在有效期內(將證書序列號經過在線證書狀態協議「OCSP」發送給CA作校驗)。
  • 證書校驗成功,最後將從證書中取出網站方的公鑰,用於後面的握手簽名。

4. Server Key Exchange

  • 這個步驟是密鑰協商的服務端部分,最終的密鑰將會用於傳輸數據對稱加密。
  • 服務端須要發送一個Diffie-Hellman算法的公鑰,和指定使用哪一種橢圓曲線多項式。
  • 咱們到Client Key Exchange的時候,再來說這個密鑰協商過程。
  • 這裏還有一個簽名,校驗這個流程的數據是否被篡改。以下圖所示,客戶端收到Server Key Exchange數據後,能夠用上個流程中得到的證書公鑰對簽名值解密,得到摘要A。並將此次數據明文作SHA512的hash,得到摘要B,作比對。(這裏對協商算法作簽名校驗,目的多是防止中間人對協商算法方式作篡改,雖然DH算法不擔憂公鑰在不安全的網絡中傳輸,可是其餘算法可能須要考慮被篡改的狀況。因此猜想服務端密鑰協商時作簽名是這個目的,由於服務端這時已經肯定是DH算法了,因此客戶端協商時就不須要作簽名了,DH算法不須要考慮這個安全問題)
  • 發送的數據以下圖示:

5. Server Hello Done

  • 服務端發送ServerHelloDone消息表示,已經發送完了密鑰協商須要的消息,而且客戶端能夠開始進行客戶端的密鑰協商處理了,也就是Client Key Exchange。
  • 收到ServerHelloDone後,客戶端須要確認服務器是否提供了合法的證書,而且確認服務器的ServerHello消息裏面的參數是否能夠接受。

6. Client Key Exchange

  • 客戶端生成本身用於密鑰協商的公私鑰,併發送此公鑰
  • 這時客戶端已經知道了服務端密鑰協商的公鑰以及本身的公鑰
  • 咱們以EC Diffie-Hellman密鑰協商協議爲例,來看看客戶端、服務端是怎麼協商出相同的密鑰的(這裏協商出來的是PreMasterSecret,不是最終的對稱加密用到的密鑰)。
  • EC Diffie-Hellman使用到一個數學難題,就是在給定的橢圓曲線上的一個點P,一個整數k,求Q=kP很容易;可是給定一個點P、Q,知道Q=kP,求整數k確實很難。
  • 服務端肯定了密鑰協商算法爲「EC Diffie-Hellman」,發送給客戶端。如今兩端都知道了使用的是哪一個曲線參數(橢圓曲線E、階N、基點G)。
  • Server Key Change:服務端隨機生成一個整數a,計算A=a*G,生成服務端公鑰A,發送給客戶端。
  • Client Key Change:客戶端隨機生成一個整數b,計算B=b*G,生成服務端公鑰B,發送給服務端。
  • 客戶端計算出PreMasterSecret:Q=bA=b(a*G)
  • 服務端計算出PreMasterSecret:Q'=aB=a(b*G),這兩個計算結果是相等的,此時雙方協商好對稱密鑰值。
  • 而且即便攻擊者截獲到雙方公鑰A、B,仍然沒法計算出PreMasterSecret,由於攻擊者須要知道隨機整數a、b的其中任意一個,但是以前咱們就提到過EC Diffie-Hellman協議中,知道A、G求a是很難的。
  • 真正對稱加密使用到的密鑰生成(這裏使用到了client、server一開始hello中傳輸的隨機數):
    • MasterSecret = PRF(PreMasterSecret, "master secret", Client.random || Server.random)[0..47] -- 固定取前 48 字節
    • KeyBlock = PRF(MasterSecret, "key expansion", Server.random || Client.random) -- 長度爲由雙方肯定的密碼算法套件決定
    • KeyBlock纔是最終用來作對稱加密的密鑰塊 6.3. Key Calculation

7. Client Change Cipher Spec

  • 這個過程就是告訴服務端,他已經準備好MasterSecret了,能夠進行數據加密傳輸了。
  • 這個協議是冗餘的,在TLS 1.3裏面直接被刪除了。

8. Client Finished

  • 這條消息是用來肯定雙方的MasterSecret是否正確生成,發送的是verify_data消息。
struct { opaque verify_data[verify_data_length]; } Finished; verify_data PRF(master_secret, finished_label,Hash(handshake_messages)) [0..verify_data_length-1]; 
  • verify_data = PRF(master_secret, finished_label, Hash(handshake_messages))
    • PRF是僞隨機函數(pseudorandom function,PRF)
    • master_secret是密鑰協商時,計算出來的
    • finished_label:對客戶端發的Finished消息來講,固定是字符串 "client finished". 對服務器發的Finished消息來講,固定是字符串 "server finished".
    • handshake_messages,是各端握手過程當中發送的全部消息的,類型以下:
      struct { HandshakeType msg_type; /* handshake type */ uint24 length; /* bytes in message */ select (HandshakeType) { case hello_request: HelloRequest; //HelloRequest是服務端在任什麼時候候均可以發出的,告訴客戶端須要從新進行握手協議,客戶端隨即發送新的ClientHello case client_hello: ClientHello; case server_hello: ServerHello; case certificate: Certificate;//服務端或客戶端發送本身證書給客戶端。 case server_key_exchange: ServerKeyExchange; case certificate_request: CertificateRequest;//服務端請求,客戶端發送本身的客戶端證書,給服務端作校驗。這個步驟在博文中沒有提到,看之後有須要再瞭解。 case server_hello_done: ServerHelloDone; case certificate_verify: CertificateVerify;//客戶端發出,從client hello開始,一直到CertificateVerify以前的全部消息的hash加上客戶端證書對應私鑰的加密結果。 case client_key_exchange: ClientKeyExchange; case finished: Finished; } body; } Handshake; 
  • 但不包括ChangeCipherSpec、alerts之類的消息。而且最後一個發送Finished的一方,須要把前一個發送Finished的內容包括進去。
  • 注意這裏每一個端發送本身的握手消息就能夠,好比Client發送內容包括ClientHello、Certificate(有發送的話)、CertificateVerify(若是有發送的話)、ClientKeyExchange、Finished(若是是最後一方須要包含)。服務端同理。

  • 由於verify_data是加密的,我就沒有在截圖了,上述的字段以及說明能夠查看協議文檔 7.4.9. Finished

8.1. Server New Session Ticket

  • 若是服務端想使用Ticket方式存儲session狀態,在Server Change Cipher Spec以前就須要發送New Session Ticket消息。
  • New Session Ticket方式與Session ID方式對比:
    • SessionID方式,客戶端在ClientHello的時候帶着上一次SessionID過來,服務端從本身內存中查找SessionID對應的session狀態,並讀取session狀態快速恢復。
    • SessionTicket方式,則是將session狀態加密後,發送給客戶端存儲。客戶端在ClientHello時將SessionTicket帶上,服務端就將其解密,讀取出裏面存儲的session狀態信息,SessionTicket存儲的信息以下:
      struct { ProtocolVersion protocol_version; //協議版本 CipherSuite cipher_suite; //加密套件類型 CompressionMethod compression_method; //壓縮方法 opaque master_secret[48]; //對稱密鑰 ClientIdentity client_identity; //客戶端ID uint32 timestamp;//ticket有效期 } StatePlaintext; 

9. Server Change Cipher Spec

  • 告訴客戶端,我已經準備好進行加密傳輸了。

10. Server Finished

  • 與8. Client Finished的狀況同樣,使用對稱密鑰加密,最後作一次驗證,肯定雙方是否都準備好進行數據傳輸了。只是這裏加密的數據還不是真正的網站內容數據,而是握手過程的數據。

11. Application Data

  • 真正的網站數據傳輸,可是這裏的數據就是通過握手時協商好的對稱密鑰進行加密的了。
  • 如今咱們有KeyBlock(對稱密鑰塊),也知道對稱加密算法是AES-128-GCM 5.1. AEAD_AES_128_GCM

參考文獻

相關文章
相關標籤/搜索