真正“搞”懂HTTPS協議18之TLS特性解析

  上一篇,我們講了TLS的握手過程,我們參照的版本其實是TLS1.2。這個協議是2008年的老協議了,雖然它的價值不言而喻,但是畢竟年紀大了,不太能跟得上時代了。所以,經歷了諸多磨難的TLS1.3在2018年也登場了,再次確立了信息安全領域的新標準。那我們先來看看TLS1.3有哪些改進。

一、最大化兼容性

  由於1.1、1.2等協議已經出現了很多年,很多應用軟件、中間代理等(官方被稱爲“MiddleBox”)只認老的記錄協議格式,就像是HTTP/3拋棄了TCP作爲底層的原因類似。更新改造很困難,甚至是不可能的。

  在早期的試驗中發現,一旦變更了記錄頭字段裏的版本號,也就是由 0x303(TLS1.2)改爲 0x304(TLS1.3)的話,大量的代理服務器、網關都無法正確處理,最終導致 TLS 握手失敗。

  爲了保證這些被廣泛部署的“老設備”能夠繼續使用,避免新協議帶來的“衝擊”,TLS1.3 不得不做出妥協,保持現有的記錄格式不變,通過“僞裝”來實現兼容,使得 TLS1.3 看上去“像是”TLS1.2。

  那怎麼辦呢?在針對這種協議升級導致的向下兼容問題,其實解決的方案都是殊途同歸。就只能包含舊的協議了唄。

  在TLS1.3中,用了一個新的“擴展協議”(Extension Protocol),它有點“補充條款”的意思,通過在記錄末尾添加一系列的“擴展字段”來增加新的功能,老版本的 TLS 不認識它可以直接忽略,這就實現了“後向兼容”。

  在記錄頭的 Version 字段被兼容性“固定”的情況下,只要是 TLS1.3 協議,握手的“Hello”消息後面就必須有“supported_versions”擴展,它標記了 TLS 的版本號,使用它就能區分新舊協議。

Handshake Protocol: Client Hello
    Version: TLS 1.2 (0x0303)
    Extension: supported_versions (len=11)
        Supported Version: TLS 1.3 (0x0304)
        Supported Version: TLS 1.2 (0x0303)

  TLS1.3 利用擴展實現了許多重要的功能,比如“supported_groups”、“key_share”、“signature_algorithms”、“server_name”等,這些等後面用到的時候再說。

二、強化安全

  TLS1.2 在十來年的應用中獲得了許多寶貴的經驗,陸續發現了很多的漏洞和加密算法的弱點,所以 TLS1.3 就在協議裏修補了這些不安全因素。比如:

  • 僞隨機數函數由 PRF 升級爲 HKDF(HMAC-based Extract-and-Expand Key Derivation Function);
  • 明確禁止在記錄協議裏使用壓縮;
  • 廢除了 RC4、DES 對稱加密算法;
  • 廢除了 ECB、CBC 等傳統分組模式;
  • 廢除了 MD5、SHA1、SHA-224 摘要算法;
  • 廢除了 RSA、DH 密鑰交換算法和許多命名曲線。

  嗯……瞭解下就行了。

  經過這一番瘦身後,TLS1.3只保留了AES、ChaCha20對稱加密算法,分組模式只能用 AEAD 的 GCM、CCM 和 Poly1305,摘要算法只能用 SHA256、SHA384,密鑰交換算法只有 ECDHE 和 DHE,橢圓曲線也被“砍”到只剩 P-256 和 x25519 等 5 種。

  算法精簡後帶來了一個意料之中的好處:原來衆多的算法、參數組合導致密碼套件非常複雜,難以選擇,而現在的 TLS1.3 裏只有 5 個套件,無論是客戶端還是服務器都不會再犯“選擇困難症”了。

   至於爲啥會廢除RSA和DH密鑰交換算法呢?因爲它不具備“前向安全”(Forward Secrecy)。什麼意思呢?

  假設有這麼一個很有耐心的黑客,一直在長期收集混合加密系統收發的所有報文。如果加密系統使用服務器證書裏的 RSA 做密鑰交換,一旦私鑰泄露或被破解(使用社會工程學或者巨型計算機),那麼黑客就能夠使用私鑰解密出之前所有報文的“Pre-Master”,再算出會話密鑰,破解所有密文。這就是所謂的“今日截獲,明日破解”。

  而 ECDHE 算法在每次握手時都會生成一對臨時的公鑰和私鑰,每次通信的密鑰對都是不同的,也就是“一次一密”,即使黑客花大力氣破解了這一次的會話密鑰,也只是這次通信被攻擊,之前的歷史消息不會受到影響,仍然是安全的。所以現在主流的服務器和瀏覽器在握手階段都已經不再使用 RSA,改用 ECDHE,而 TLS1.3 在協議裏明確廢除 RSA 和 DH 則在標準層面保證了“前向安全”。

三、提升性能

  HTTPS 建立連接時除了要做 TCP 握手,還要做 TLS 握手,在 1.2 中會多花兩個消息往返(2-RTT),可能導致幾十毫秒甚至上百毫秒的延遲,在移動網絡中延遲還會更嚴重。

  現在因爲密碼套件大幅度簡化,也就沒有必要再像以前那樣走複雜的協商流程了。TLS1.3 壓縮了以前的“Hello”協商過程,刪除了“Key Exchange”消息,把握手時間減少到了“1-RTT”,效率提高了一倍。咋搞的呢?

  其實具體的做法還是利用了擴展。客戶端在“Client Hello”消息裏直接用“supported_groups”帶上支持的曲線,比如 P-256、x25519,用“key_share”帶上曲線對應的客戶端公鑰參數,用“signature_algorithms”帶上簽名算法。

  服務器收到後在這些擴展裏選定一個曲線和參數,再用“key_share”擴展返回服務器這邊的公鑰參數,就實現了雙方的密鑰交換,後面的流程就和 1.2 基本一樣了。我們來看張熟悉的圖:

  對比之前的圖,有啥區別呢?在第一次傳遞記錄的時候,就把支持的版本號吖、key_share等等傳遞給了服務器,服務器就可以根據這些字段處理數據返回給客戶端,換句話說,其實就是打個提前量,減少請求次數。

  其實誇張一點,所有的數據交換,來回一次就夠了,只需要一個往返,你品品?

四、握手分析

  我們直接看下它的流程圖,注意對比上一小節的詳細握手圖,看看它們的區別。

  還是四個步驟,我們來過一下噢~

  首先還是TCP的三次握手,握手建立TCP連接後,瀏覽器還是首先發個“Client Hello”,因爲 1.3 的消息兼容 1.2,所以開頭的版本號、支持的密碼套件和隨機數(Client Random)結構都是一樣的(不過這時的隨機數是 32 個字節)。

Handshake Protocol: Client Hello
    Version: TLS 1.2 (0x0303)
    Random: cebeb6c05403654d66c2329…
    Cipher Suites (18 suites)
        Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
        Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
        Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
    Extension: supported_versions (len=9)
        Supported Version: TLS 1.3 (0x0304)
        Supported Version: TLS 1.2 (0x0303)
    Extension: supported_groups (len=14)
        Supported Groups (6 groups)
            Supported Group: x25519 (0x001d)
            Supported Group: secp256r1 (0x0017)
    Extension: key_share (len=107)
        Key Share extension
            Client Key Share Length: 105
            Key Share Entry: Group: x25519
            Key Share Entry: Group: secp256r1

  注意“Client Hello”裏的擴展,“supported_versions”表示這是 TLS1.3,“supported_groups”是支持的曲線,“key_share”是曲線對應的參數。

  服務器收到“Client Hello”同樣返回“Server Hello”消息,還是要給出一個隨機數(Server Random)和選定密碼套件。

Handshake Protocol: Server Hello
    Version: TLS 1.2 (0x0303)
    Random: 12d2bce6568b063d3dee2…
    Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
    Extension: supported_versions (len=2)
        Supported Version: TLS 1.3 (0x0304)
    Extension: key_share (len=36)
        Key Share extension
            Key Share Entry: Group: x25519, Key Exchange length: 32

  表面上看和 TLS1.2 是一樣的,重點是後面的擴展。“supported_versions”裏確認使用的是 TLS1.3,然後在“key_share”擴展帶上曲線和對應的公鑰參數。

  這時只交換了兩條消息,客戶端和服務器就拿到了四個共享信息:Client Random 和 Server Random、Client Params 和 Server Params,兩邊就可以各自用 ECDHE 算出“Pre-Master”,再用 HKDF 生成主密鑰“Master Secret”,效率比 TLS1.2 提高了一大截。

  在算出主密鑰後,服務器立刻發出“Change Cipher Spec”消息,比 TLS1.2 提早進入加密通信,後面的證書等就都是加密的了,減少了握手時的明文信息泄露。

  這裏 TLS1.3 還有一個安全強化措施,多了個“Certificate Verify”消息,用服務器的私鑰把前面的曲線、套件、參數等握手數據加了簽名,作用和“Finished”消息差不多。但由於是私鑰簽名,所以強化了身份認證和和防竄改。

  這兩個“Hello”消息之後,客戶端驗證服務器證書,再發“Finished”消息,就正式完成了握手,開始收發 HTTP 報文。

  我們可以看到,其實就是在第一次傳遞消息的時候,通過擴展協議,減少數據的往返,提前進入數據傳遞的時間。

五、小結

  其實這篇文章和上一篇文章的重點都在於圖中,大家要好好消化。要注意TLS1.3相比於TLS1.2有哪些不同點,其實核心就是通過擴展協議來提前把需要參數交換,嗯……就這麼簡單。

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章