27丨更好更快的握手:TLS1.3特性解析


說明《透視HTTP協議》是 羅劍鋒 (奇虎360技術專家)在極客時間開的一門專欄課,筆者記錄一下學習筆記,僅供參考。

上一講中我講了 TLS1.2 的握手過程,你是不是已經完全掌握了呢?

不過 TLS1.2 已經是 10 年前(2008 年)的“老”協議了,雖然歷經考驗,但畢竟“歲月不饒人”,在安全、性能等方面已經跟不上如今的互聯網了。

       於是經過四年、近 30 個草案的反復打磨,TLS1.3 終於在去年(2018 年)“粉墨登場”,再次確立了信息安全領域的新標准。

       在抓包分析握手之前,我們先來快速瀏覽一下 TLS1.3 的三個主要改進目標:兼容安全與性能

最大化兼容性

       由於 1.1、1.2 等協議已經出現了很多年,很多應用軟件、中間代理(官方稱為“MiddleBox”)只認老的記錄協議格式,更新改造很困難,甚至是不可行(設備僵化)。

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

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

       那么,該怎么區分 1.2 和 1.3 呢?

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

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

       其實上一講 Chrome 在握手時發的就是 TLS1.3 協議,你可以看一下“Client Hello”消息后面的擴展,只是因為服務器不支持 1.3,所以就“后向兼容”降級成了 1.2。

 

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 種。

       減肥可以讓人變得更輕巧靈活,TLS 也是這樣。

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

 

       這里還要特別說一下廢除 RSA 和 DH 密鑰交換算法的原因。

       上一講用 Wireshark 抓包時你一定看到了,瀏覽器默認會使用 ECDHE 而不是 RSA 做密鑰交換,這是因為它不具有“前向安全”(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 基本一樣了。

我為 1.3 的握手過程畫了一張圖,你可以對比 1.2 看看區別在哪里。

 

       除了標准的“1-RTT”握手,TLS1.3 還引入了“0-RTT”握手,用“pre_shared_key”和“early_data”擴展,在 TCP 連接后立即就建立安全連接發送加密消息,不過這需要有一些前提條件,今天暫且不說。

握手分析

       目前 Nginx 等 Web 服務器都能夠很好地支持 TLS1.3,但要求底層的 OpenSSL 必須是 1.1.1,而我們實驗環境里用的 OpenSSL 是 1.1.0,所以暫時無法直接測試 TLS1.3。

不過我在 Linux 上用 OpenSSL1.1.1 編譯了一個支持 TLS1.3 的 Nginx,用 Wireshark 抓包存到了 GitHub 上,用它就可以分析 TLS1.3 的握手過程。

 

       在 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”擴展帶上曲線和對應的公鑰參數。

服務器的“Hello”消息大概是這個意思:

       “還真讓你給猜對了,雖然還是按老規矩打招呼,但咱們來個‘舊瓶裝新酒’。剛才你給的我都用上了,我再給幾個你缺的參數,這次加密就這么定了。”

       這時只交換了兩條消息,客戶端和服務器就拿到了四個共享信息:Client RandomServer RandomClient ParamsServer 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.3,比如NginxGitHub,你可以課后自己用 Wireshark 試試。

       在 Chrome 的開發者工具里,可以看到這些網站的 TLS1.3 應用情況。

 

小結

今天我們一起學習了 TLS1.3 的新特性,用抓包研究了它的握手過程,不過 TLS1.3 里的內容很多,還有一些特性沒有談到,后面會繼續講。

為了兼容 1.1、1.2 等“老”協議,TLS1.3 會“偽裝”成 TLS1.2,新特性在“擴展”里實現;

1.1、1.2 在實踐中發現了很多安全隱患,所以 TLS1.3 大幅度刪減了加密算法,只保留了 ECDHE、AES、ChaCha20、SHA-2 等極少數算法,強化了安全;

TLS1.3 也簡化了握手過程,完全握手只需要一個消息往返,提升了性能。

課下作業

TLS1.3 里的密碼套件沒有指定密鑰交換算法和簽名算法,那么在握手的時候會不會有問題呢?

結合上一講的 RSA 握手過程,解釋一下為什么 RSA 密鑰交換不具有“前向安全”。

TLS1.3 的握手過程與 TLS1.2 的“False Start”有什么異同?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM