文|曾柯(花名:毅絲 )
螞蟻集團高階工程師\
負責螞蟻集團的接入層建設工作 主要方向為高效能安全網路協議的設計及優化
本文 10924 字,閱讀 20 分鐘
PART. 1 引言
從前一篇文章《深入 HTTP/3(1)|從 QUIC 連結的建立與關閉看協議的演進》對於 QUIC 的淺述中我們瞭解到,QUIC 的優化很大程度上是一種基於 TLS 流程的優化,由此也可見 TLS 對於 QUIC 的重要性,那麼今天我們就來聊一聊 QUIC-TLS。為了表述儘量沒有歧義,我們先來規範下文章中各個術語的意義。
本文目前既然已經提到了 SSL、TLS 這兩個術語,我們不妨先來簡短回顧下安全協議的發展史,這既可以幫我們理清兩個術語的關係,也能幫助我們對這項技術的進化有一個簡短的概念。
SSL (Secure Sockets Layer) 協議本身是網景公司為了保證網際網路上資料傳輸的安全性,在 1994 年設計的一套協議。這套協議在當時被廣泛使用在各大瀏覽器上,但 SSL 協議最初的幾個版本安全性都非常堪憂,初期的更迭非常頻繁,從 1994 年到 1995 年連續迭代了 3 個大版本,而現在大家最耳熟能詳的應該就是 SSLv3.0 了。可惜 SSLv3.0 也沒有逃脫更迭的厄運,由於硬體算力的迭代,大量 SSLv3.0 中廣泛使用的加密演算法不再安全,並且協議互動流程也存在不安全之處。1999 年,IETF 正式介入安全協議的設計及開發,並推出了 TLS (Transport Layer Security) 協議的第一個版本 TLS1.0,隨後 TLS 協議的發展開始變得遲緩,在 2006 年 IETF 組織推出了 TLS1.1,並在 2008 年再次釋出了 TLS1.2,兩個版本都是針對一些握手互動過程中的細節的安全提升,握手流程其實是沒有大的變化的。
直到 2013 年,Google 在推出 gquic 的同時,也推出了其設計的安全互動流程 quic-crypto,quic-crypto 是一次互動流程的重大創新,也以此成為了 TLS1.3 的前身。TLS1.3 從某種意義上來說,應該被稱作 TLS2.0,因為其革新力度非常大,當然這也導致其標準化流程非常長,TLS1.3 的標準化整整歷經了 4 年,直到 2018 年才正式成為 RFC。而 TLS1.3 本身也成為了 IETF-QUIC 的安全互動技術的基礎,所以這條時間線裡也揉雜了 QUIC-TLS 的設計歷程,我們來簡單理一下:
圖 1. TLS 發展簡史
當然 DTLS 等相關安全技術的進化也融合在這條時間線中,限於篇幅問題,這裡暫時不表。說了這麼多廢話,我們現在來正式標準化一下我們的名詞:
【SSL、TLS】 :在本文中都指安全傳輸協議,後續的文章中只會使用 TLS 作為相關技術的代名詞
【QUIC-crypto】 :Google quic 中使用的握手流程,本文不對其進行具體分析
【QUIC-TLS】 :本文指 IETF-QUIC 使用的安全互動流程,即 RFC9001 中標準化的流程,也是本文詳細描述的重點
【PTO】 :全稱為 Probe Timeout,定義於 RFC9002 中,留待下一篇文章來對其進行詳細分析,本文將其理解成一個通訊端設定的針對報文的超時重傳的時間即可
【DTLS】 :全稱為 Datagram Transport Layer Security,即面向報文的 TLS 協議,限於篇幅的問題,本文並不詳細對其分析,而 DTLS 中存在有很多和 QUIC-TLS 類似思路的設計,感興趣的同學可以參見 RFC9147
“make infrastructure boring”是 Google 一直以來的口號,BoringSSL 這個開源產品則是他們在安全通訊領域的行動,而文章的標題既然叫“不那麼 Boring 的 SSL”,除了蹭一蹭 BoringSSL 和 OpenSSL 這些著名的 SSL 開源專案的熱度之外,也是想給文章製造一點懸念:Boring 往往意味著相關技術簡單好用到了令人髮指的地步,而 QUIC 到底遇見了什麼問題,才讓本身相對成熟的 TLS 協議用起來不再 Boring?
本文後續也將圍繞這個話題展開,來看看 QUIC-TLS 設計中那些值得玩味的地方。
PART. 2 淺看 TLS
本著由淺入深的思路,在開始介紹 QUIC-TLS 之前,我們也先淺析一下 TLS,這也非常有助於我們後面對於 QUIC-TLS 的理解。
TLS 協議從某種程度上來說解決了幾個哲學問題:
你是誰?你怎麼證明你是你?
當然這些問題的答案還不足以保證整個的安全...
1. 我們還需要一種技術來保證中間人無法獲取到我們的資料,這也就是我們相對比較熟悉的 「對稱加密技術」,比如 AES、SM4 等加密技術;
2. 為了加密的資料也能證明通訊一端的身份,我們引入了 「AEAD 加密即認證的模式」;
3. 為了協商出這種對稱加密的金鑰,TLS 引入了 「非對稱金鑰交換技術」,典型如 ECDHE、RSA 等金鑰交換演算法;
4. 為了身份管理的統一及身份的有效攜帶,TLS 引入了 「數字證書技術」,包括整個 pki 公鑰體系及 X509 數字證書標準;
5. 為了資料的不可篡改,TLS 引入了 「數字簽名技術」,典型如 ECDSA、RSA 等簽名演算法;
6. 為了各個階段的加密金鑰獨立及簽名流程的簡潔,TLS 引入了 「Hash 演算法」,典型如 SHA 系列演算法。
上述的各種機制再整個 TLS 協議中被抽象為兩部分協議:
一層是 Handshake 協議,負責核心金鑰的互動及身份認證;一層是 Record 協議,負責資料的安全,完整性及握手完成後資料的可信證明,而 Handshake 協議則坐落於 Record 協議之上,這也就形成了這樣的協議棧。
圖 2. TLS 協議棧簡圖
簡而言之,Handshake 過程中的資料也依賴 Record 層來進行資料加密,而 Record 層加密的 key 則依賴 Handshake 層進行互動得到。這看似是個邏輯死鎖,實際上是通過一個層層遞進的狀態機完成的,拋開繁瑣的 TLS 狀態機本身,這個流程基本可以用下圖來表述:
圖 3. TLS 金鑰狀態更新流程圖
至於 TLS 的初始階段使用明文傳輸的資料,也並不違背這個流程,我們可以將其理解為 TLS 初始階段對應一個值為空的 key。而從上圖中我們也可以看到,實現和虛線部分對應的兩個階段切換,必須有嚴格的先後順序,如果發生亂序,一端是無法完成資料的解析的,所以 TLS 協議非常依賴底層傳輸協議來保證資料的有序到達,而這也是 TLS 的設計區別於 DTLS 和 QUIC-TLS 的最大根因之一。有了這部分知識儲備,我們再來看 TLS 的握手 (以 TLS1.3 的 0-RTT 互動場景為例) ,就會清晰很多:
圖 4. TLS 握手流程圖
可以看到,明文"()","{}","[]"對應的加密狀態的切換,和上面的圖的流程基本是一致的,而典型如 EndOfEarlyData 這種標示資料,就是用來通知對端的金鑰狀態切換的,這部的理解對於我們後面理解 QUIC-TLS 的設計大有用處。
在這一章的最後,我們對 TLS 做一個簡單總結:
圖 5. TLS 小結
而在使用層面來說,TLS 通過一層安全的抽象,讓應用層可以直接通過一個簡單的 SSL_read/SSL_write (以 OpenSSL/BoringSSL 為例) 讀寫介面,就可以直接使用安全通訊的能力,而完全不需要關注 TLS 握手,狀態轉換的細節。
從這個角度來說,使用 TLS 已經足夠 Boring 了,而從安全訴求上來說,本身 QUIC-TLS 和 TLS 是一致的,也不應該會有大的出入,那麼又是什麼讓 QUIC-TLS 變得如此複雜呢?
PART. 3 深入 QUIC-TLS 的不同之處
在我們上一篇文章裡,我們已經對 QUIC 建聯進行了分析,為了保證 QUIC 建聯的高效,QUIC 將有序和安全融合在了一起。而我們知道,TLS 本身是基於 TCP 設計的協議,兩者之間有嚴格的分層,而 TCP 協議保證了所有資料都被成功,且有序的傳輸到了對面,所以 TLS 便不需要再考慮丟包和亂序的問題。而 QUIC-TLS 則需要將兩者合在一起考慮,回顧前文,我們知道 QUIC 為了不協商即可在第一個報文開始有序傳輸,引入了 pkt number 和每個幀的 offset 機制,並且兩個標示均從 0 開始,然後由 TLS 來保證其安全性,細心的讀者可能已經發現這其中邏輯的迴圈依賴了。
圖 6. TLS 的協議依賴
為了解開這個死迴圈,QUIC-TLS 必須將安全層面的互動做更細粒度的拆分,才能夠實現既安全又可靠的傳輸,因此在 RFC9001 中我們可以看到,QUIC 的協議棧看起來會是這個樣子:
圖 6. QUIC-TLS 協議棧
這個圖和前面 TLS 協議棧有點像,但又不那麼像。我們已經知道,協議棧層層分層的效果就是上層協議生成的報文會按照 payload 的形式塞在其下一層的協議中,QUIC Packet Protection 協議作為保護資料安全的協議,那麼其職責和 TLS Record 是類似的,而 QUIC Transport 協議 (保證 QUIC 可靠有序傳輸) 這部分則和 TCP 類似,可以看到 QUIC 協議棧的下半部分是完全和 TLS+TCP 的協議棧相反的,這也就意味這 QUIC-TLS 的設計在底層上必然和 TLS 的設計不盡相同,我們來深入拆解一下。
1. 以包為基本單位的加密策略
我們已經知道了 Record 層的功能靠的是對稱加密演算法來保證安全,並用 AEAD 的加密模式來保證資料的可信,以一個典型的例項演算法 AES-128-GCM 為例,AES-128 表示對稱加密演算法為 AES-128,GCM 其對應的 AEAD 演算法,AES-128-GCM 加密擁有四個輸入:
(1) 待加密明文 plaintext; \
(2) 加密的金鑰 key; \
(3) 加密的隨機數 Nonce; \
(4) 認證的關聯資料 Associate Data。
其解密也基本一致,僅將明文換成加密後的密文 ciphertext 即可。對於 Nonce 這個值,在 TLS 中由於本身不用考慮資料的有序傳輸,Nonce 是通過 client 和 server 自己為每個 Record 報文維護一個技術器來實現的,即 Nonce 從 0 開始,每收到一個對端的 Record 報文自加 1。
對於 QUIC-TLS,通過加密演算法實現資料的安全傳輸也逃不開這一套機制。然而對於 QUIC-TLS 而言,由於安全和有序已經融合在了一起,我們每收到一個報文,需要先解密才知道報文是不是亂序,所以我們不能通過維護計數器的方式來實現自增 Nonce 的這個功能,怎麼辦呢?
我們恰好看到有 packet number 這樣一個單調自增的值 (注意 packet number 的功能並不是為了作為 Nonce,其具體的作用我們留到後面 QUIC 的丟包檢測部分再深入分析) ,非常適合作為 Nonce。但 packet number 本身又是需要加密的,這要怎麼處理呢?解決方案也不復雜,那就是 packet number 使用較為弱的加密模式,即最簡單的 ECB 模式來加密,以 AES-128-ECB 為例,這種模式加/解密只需要兩個輸入:
(1) 待加密明文 plaintext/待解密的密文 ciphertext; (2) 加密的金鑰 key。
再次回顧之前關於 TLS 的狀態轉換的圖,只要我們能按照這樣的狀態轉換不斷的更新 key,我們就可以按照下面的流程去解開 pkt number,並以此為基礎進一步解密得到握手/應用層的資訊。 (注意其中的步驟 3、4 並不一定有嚴格的順序之分,因為 QUIC 的丟包檢測等不僅是依賴 pkt number,也依賴一些特殊的控制幀。關於這部分,我們留到後面關於 QUIC 的丟包檢測的相關文章中進行分享。)
圖 7. QUIC-TLS 的包處理
瞭解了這一步,我們也就明確了為什麼 QUIC 在安全層面會選擇以 QUIC packet 作為基本單位的原因。當然,一次 QUIC-TLS 握手過程中會有多個狀態,也就是有多個不同加密的 key,為了讓 QUIC 的互動過程更清晰,QUIC 也定了 6 中不同型別的 Packet,用來對應 6 種狀態,也就是 6 種加密的 key。
圖 8. QUIC-TLS 的包加密等級
其中 Initial 部分對應的則是 TLS 過程中明文傳輸的部分,這部分資料雖然在名義上也是加密了的,但其加密的 key 是一個寫死在 RFC 裡的,人人都知道的值,也就相當於明文傳輸了。這種做法倒不能說是多此一舉,因為這確實也在某種程度上提升了攻擊者的攻擊成本,但它的確不能保證 ClientHello 這部分資料的安全。為此,QUIC-V2 也準備引入 Encrypted-ClientHello 等安全技術來對這部分資料進行保護,這個我們在後文再慢慢分享。
這種區分了 pkt type 的包加密模式,讓資料有了更清晰的狀態轉移標識。我們再來回頭看一看 TLS 的狀態轉移圖,可以發現每次通知對端從 key1 切換到 key2 時,一定是會先傳送一個用 key1 加密的通知訊息 (即 TLS 中的 ChangeCipherSpec) ,才會再去發 key2 加密的資料的,這樣才能從理論上保證對端能夠成功處理通知訊息,完成 key 狀態的變化。而在 QUIC-TLS 中,包的 pkt type 則成為了這樣一個顯式的通知狀態轉移的標識,比如對端開始響應 Handshake 包了,就說明狀態就是要轉移到 Handshake 狀態了,而這也就讓 QUIC-TLS 不再需要 ChangeCipherSpec 以及 EndofEarlyData 這一類的顯式通知對端的機制,並且這對於握手過程的亂序處理有很大幫助。有了這些儲備知識,我們再來深入看看 QUIC-TLS 握手的細節,就更容易把握其本質。
2. 不嚴格的分層,帶來更加嚴格的 0-RTT 使用限制
0-RTT 功能的雛形來自於 QUIC-crypto,並在 TLS1.3 中被正式標準化,也成為了一個 TLS1.3 非常吸引使用者的點,然而該功能的使用條件卻非常苛刻。
首先,0-RTT 依賴 TLS 的會話複用的成功,這也就意味著其使用流程必須存在著互動確認的機制,否則 client 初始階段一股腦的發 0-RTT 資料過去,卻又無法被 server 確認接收,那麼這就是對資源的一種浪費;
其次,0-RTT 資料本身涉及到金鑰狀態的轉換,那麼也就需要為其設計相應的狀態轉換機制 (及前文的 EndOfEarlyData) ;
最後,0-RTT 資料本身是不安全的,因為其完全不能避免重放攻擊,只能依靠應用層協議自己保證冪等。
對於第一個問題,QUIC-TLS 和 TLS1.3 並無太大差別,都是通過 server 的響應裡的擴充套件來說明是否接收 0-RTT 資料的,而第二個問題前文我們也已經分析過,QUIC-TLS 依靠包的顯式加密等級,也不需要 EndOfEarlyData 這種機制來通知金鑰狀態需要轉換。但到了問題 3,要考慮的情況就會複雜很多,我們先從 QUIC 層面出發來看,我們知道 QUIC 通過 STREAM 型別的幀來承載應用層資料,但除了承載資料之外,QUIC 也提供了諸如 RESET_STREAM, STOP_SENDING 這一類用於控制應用層資料傳輸的控制幀,而這些都是重放不安全的。
那麼在 QUIC 的角度上來看,除非你知道自己的應用層協議如何在操作 QUIC 的 stream,並且有明確的能力去保證這些行為的重放安全,你才能去用這個能力,否則乾脆將其束之高閣,RFC9001 中對此也是提出了明確的建議。
而我們再站到 HTTP/3 的角度來看一下,上一篇文章裡我們提到過,HTTP/3 並不是 QUIC+HTTP/2,而是將 HTTP/2 中流這部分的抽象交給了 QUIC,然後在 HTTP/3 裡去控制這些流。從這一點來看,HTTP/3 原生的符合了 QUIC-TLS 中對於 0-RTT 能力使用的要求,但我們仍有諸多問題需要考慮,因為 QUIC 本身是一個對於連結以及連結上的流有諸多可配置引數的協議。當 client 要開始傳應用層資料的時候,往往就意味著底層的傳輸條件已經協商好了 (而由於 HTTP/3 和 QUIC 的繫結關係,這些傳輸引數還包含著 HTTP/3 的一些語義) ,而 client 傳輸 0-RTT 資料時,我們無法通過協商去獲取這些引數,而只能通過之前的連結引數來繼續傳輸,所以對於叢集化的 QUIC 場景,保證叢集內機器配置的一致性以及變更的相容性,也是 QUIC 使用者需要注意的一大問題。
3. QUIC-TLS 握手,亂序帶來的複雜度提升
我們先來看下 RFC9001 中對於 QUIC-TLS 的互動示意圖:
圖 9. QUIC-TLS 的握手互動
僅從這個握手協議圖來看,如果我們先簡單的:
(1) 將 Init 報文當 ClientHello/ServerHello;
(2) 0-RTT 報文對應 TLS 的 0-RTT 資料;
(3) HandShake 資料對應 ServerFinish/ClientFinish。
那麼這個握手流程似乎和 TLS 並沒有什麼不同,事實上僅從握手原理來看,也確實如此。然而當我們引入亂序的考慮之後,問題複雜度就要高出不少了,我們已經在前面分析過,TLS 是依賴 TCP 的有序傳輸來保證狀態 (或者說當前加解密的 key) 的層層遞進的,也正因為資料嚴格有序,TLS 也只需要維護當前一個 key 就行。而到了 QUIC-TLS 這裡,問題就不再如此簡單了,我們可以分成兩種典型情況來討論:
一、下一階段的包提前到來
這個問題雖然在 QUIC-TLS 握手過程中有共性,但也要分階段來看,每個階段也有每個階段自己的問題特點,目前觸發這個問題其實有好幾種可能性:
- client 的 0-RTT 報文早於 Init 報文到來
- Server 的 Handshake 報文早於 Init 報文到來
- Server 的 1-RTT 報文早於 Server 的 Handshake 報文到來
- client 的 1-RTT 報文 client 的 Handshake 報文到來
對於第一種情況,其實解決方案非常簡單,由於 ClientHello 本身並不會很大,並且在首包我們只會發 1 個 0-RTT 報文 (因為並不知道 server 是否會接收 0-RTT 報文,所以先發一個嘗試一下) ,我們可以通過將 QUIC 包聚合在一個 UDP 包內傳送 (這是標準允許並且推薦的) 來從根源上解決亂序的問題。
然而後續的問題就較為複雜了,在情況 2 的條件下,由於服務端的證書可能比較大,Server 的 Handshake 包也就會很大,光靠聚合 Server 的 Init 是不能滿足要求的。試想一下,如果客戶端對於亂序的情況選擇全部快取的策略的話,中間攻擊人可以直接通過不斷髮送 HandShake 報文,來將客戶端的快取吃完的。
而 QUIC 的巧妙之處也就在這裡,協議層的耦合可以使得其他層次安全機制在當前層面也可以服用,還記得上一篇文章講的放大攻擊的防範嗎?客戶端握手完成前,服務端不允許傳送 3 倍以上的資料,直到收到客戶端的響應,客戶端可以以此為標示來應對這種場景防範。當然,從實現層面來講,大部分實現者還是會選擇直接丟棄這種亂序報文,因為維護這種快取佇列本身就是一個複雜的事。對此,RFC 也有相應的建議,服務端實現握手過程中的資料有限次的早於 PTO 結束的重傳,來加速握手的完成。
情況 3 和 4 從原理上來看,和情況 2 面臨的問題似乎也沒有很大差別,但其中涉及到的細節問題還是需要 case by case 的討論:
首先,在真實應用場景下,情況 3 卻往往不存在,而其為什麼不存在,則需要看情況 4 的問題。僅從 TLS 互動圖來看,client 的 1-RTT 資料早於 client Handshake 報文到來,server 其實此時是有 1-RTT 的 key 的,可以完成資料的解密。
但考慮這兩種情況:
(1) 在雙向認證的場景下,此時 client Handshake 中攜帶的是 client 的身份資料,server 不應該在身份驗證完成前響應用層的資料,也就不應該在握手完成前,傳送 1-RTT 的資料;
(2) 在 0-RTT 場景下,首先我們知道,0-RTT 資料對應的響應都是通過 1-RTT 報文攜帶的,但 0-RTT 資料本身由於安全問題,只能依靠應用層的冪等性來實現重放攻擊的保護。在握手沒有成功前,server 無法確認是否收完了所有 0-RTT 資料,而沒有全量資料的情況下應用層也無法確認是否資料是否是重放攻擊,所以在握手完成前,服務端也不能直接響應 0-RTT 的報文。
總的來說,出於應用層面的考慮,情況 4 有了更明確的限制,RFC9001 則直接明確規定服務端不應當在握手完成前處理 1-RTT 報文,但至於本身 UDP 層面的快取怎麼實現,就交給實現者根據自己的網路情況去斟酌了。
二、收到之前加密階段的包
剛剛我們討論的是如何處理新狀態資料的問題,那麼現在我們再看看如何維護老的狀態的問題。從 TLS 的經驗來看,似乎從直覺上來說我們並沒有維護之前加密狀態資料的必要,而 QUIC-TLS 和 TLS 也類似,如果通訊某一端成功進入了下個握手階段,那麼也意味著其已經收到了所有必要的握手訊息,那麼如果它再次之前階段的資料,這些資料要麼就是重傳,要麼就是攻擊,似乎也沒有處理的必要?
的確,如果僅從握手來看,維護上一階段的 key 是浪費的,但把 0-RTT 功能考慮進來,則就不一定了。對於 client 來說,正常情況下 0-RTT 資料的應當是早於 client 的 Handshake 報文傳送的,但由於中間網路裝置的不可控,0-RTT 資料是可能晚於 1-RTT 資料到來的,如果 server 能維持 0-RTT 的加密狀態,那麼就可以避免這些亂序包的重傳。而我們前面已經討論過,0-RTT 本身並不是一個很安全的機制,在 QUIC-TLS 中 client 應當在 1-RTT 金鑰生成後馬上將其廢除,所以 server 也沒有必要長時間維護 0-RTT 對應的加密狀態,而對於具體維護的時間的選擇,RFC9001 建議了一種類似 TCP Time_wait 的方案,即 server 只需維護 0-RTT 金鑰為 3 個 PTO,確保亂序資料在網路中自然消亡。
除了 0-RTT 的 Key 的處理,QUIC-TLS 中還有一個 Key Update 的機制,用於在握手完成後,對當前狀態的金鑰進行更新,這個機制也面臨著和亂序和新舊狀態的 key 的維護的問題,但其原理和 0-RTT 是一致的,這裡就不再贅述了。
PART. 4 再看 QUIC-TLS 協議棧
至此,我們已經瞭解了 QUIC-TLS 是如何通過各種細節機制來保證其狀態能成功層層演進了,我們不妨再回頭看下圖 6 中的 QUIC-TLS 的協議棧,可以看到,QUIC Packet Protection 這部分通過維護當前階段的 key,以及顯式加密等級的 QUIC 報文機制,可以清晰的得到明文的資料,而 QUIC Transport 這一層則提供了功能上相對獨立的可靠傳輸機制。
如此來看,上層 TLS Handshake 這部分就可以拆的很細而且實現功能上的獨立了,出於工程上的懶人思維,也是對於安全穩定性的考量,現有的 TLS 沉澱的各種能力能複用的當然要儘可能複用起來。所以我們可以看到 QUIC-TLS 裡定義瞭如何去設計 TLS 的 API,讓其剛好能和底層的 QUIC 互動使用。
圖 10. QUIC-TLS 和現有 TLS 的互動流程
至此,本文差不多完成了對 QUIC-TLS 握手階段的所有分析。可以看到,QUIC-TLS 的設計中充斥著大量層間耦合的考慮,任何一個功能點,並不是簡簡單單滿足訴求就行,既需要向上考慮上層應用協議,也需要向下考慮本身協議棧的適配。而這樣的設計,充斥著 QUIC 協議棧的各個點,我想這也就是 QUIC 歷經這麼多年才終成標準的原因之一吧。
文章寫到這裡確實有點長了,感謝各位讀者可以看到這裡。本文對於 QUIC-TLS 中涉及的很多細節流程比如 Head 保護的演算法,Retry token 的加密等,都沒有提及。
在我個人的視角來看,這些都是相對獨立,並且較為容易理解的功能,讀者自行看 RFC9001 應該就可以理解了,並不需要有什麼特殊的分析說明。
當然如果各位讀者期望對這一類技術有一個總結的話,可以在文章最後留言,後面再出一期關於這些技術的總結性文章。
PART. 5 對於 QUIC-TLS 的展望
前文說了一圈 QUIC-TLS 和 TLS 的不同,反而到展望這裡,QUIC-TLS 倒是和 TLS 的演進出奇的一致,當然這也是一個符合邏輯的結論。因為無論是 QUIC-TLS 還是 TLS,終究都是在為使用者的安全提供保障,而下一代的安全技術也往往都是在加解密等技術細節上發力,在我們肉眼可見的未來,我們也許可以在 QUIC-V2 看到這些技術的落地:
- Encrypted ClientHello:這部分已經在前文討論過,為了使 QUIC 的 Init 報文更加安全,我們可以通過公鑰加密技術和帶外公鑰同步的方式,來實現首包的加密,感興趣的讀者可見相關草案。
- Certificate Compression:證書鏈過長一致是導致弱網環境握手成功率低的重要原因之一,而對證書進行有效壓縮,會使互動資料大幅降低,提高握手成功率,感興趣的讀者可見相關標準。
- Delegated Credential:公有云、混合雲環境的安全性一直受到各種挑戰,而私鑰作為如此重要的資料,部署在公有云上也有很大的風險,通過對葉子證書籤發短期的委派憑證,可以有效的減少攻擊視窗,感興趣的讀者可見相關標準。
- 國密互動:在當前局勢下,密碼安全已經上升到了一個很高的高度,我們也在嘗試將國密演算法標準化到 QUIC-TLS 流程中,以滿足合規性和安全性的訴求。
當然各種新興技術是層出不窮的,我們也會持續不斷的跟進,以保證螞蟻相關產品的使用者在享受良好網路體驗的條件下,也能得到極致的安全保障。
PART. 6 最後帶個貨
最後的最後,看完技術分享,不如再來點產品分享及八卦時刻,OpenSSL 確實是一個不可多得的開源屆良心產品,但它在 QUIC-TLS 這個事情上確實搞的有點令人迷糊。
很早前,Akamai 的貢獻者就針對 QUIC-TLS 的功能做了 PR 提交,但是 OpenSSL 一直以 QUIC 還沒有標準化作為理由,不給予合併考慮,等到 QUIC 標準化了之後,OpenSSL 官方社群又說自己不滿足於只有 QUIC-TLS 的庫支援,要自己搞個 QUIC 的完整實現 (包括 s_client,s_server 等測試客戶端/服務端對於 QUIC 的支援) ,雖然社群充斥著大量質疑的聲音,但最終還是沒能動搖他們的決心,當然這並不說明 OpenSSL 的抉擇是錯的,因為從 OpenSSL 組織的思考來看,OpenSSL 不太滿足於當前想一個簡單的為 QUIC 提供 TLS 庫的能力的角色,他們想更進一步轉變成一個為產品提供 QUIC 庫的角色,而目前的選擇也是他們的必由之路。
當然他們的理想是遠大的,而苦的是我這種 OpenSSL 重度使用者,OpenSSL 初期開源的 PR 其實在使用過程中還是有不少小問題,社群的不支援會讓大量使用者對這部分功能持觀望態度,那麼這些細節問題就會更難暴露出來,使用者們提交 PR 的動力也會弱不少。並且由於 OpenSSL 官方的這種不支援的態度,導致大部分開源 QUIC 庫也選擇了 BoringSSL,而這對於一些既有的,已經基於 OpenSSL 實現的產品則是一種災難,這些產品想要切換到 BoringSSL 以整合相應 QUIC 庫絕不是一件容易的事。
不過好就好在,有問題總有解法,我們在我們開源的 BabaSSL 庫對 QUIC-TLS 做了全量實現,除了幫助社群原始 PR 完善其對應的功能之外,同時也相容了部分 BoringSSL 的 API 使用,這部分也經過了螞蟻的生產考驗,歡迎各位讀者來體驗一下,當然不僅如此,對於前文 QUIC-TLS 展望中提到的技術,我們也正在或者已經完成了實現,歡迎各位讀者前來嚐鮮。
瞭解更多...
BabaSSL Star 一下✨:
https://github.com/BabaSSL/BabaSSL
【參考連結】
【1】https://datatracker.ietf.org/...
【2】https://datatracker.ietf.org/...
【3】https://datatracker.ietf.org/...