讓網際網路更快:通往QUIC之路

QUIC(Quick UDP Internet Connections)是一種默認加密的新互聯網傳輸協議,它提供了多項改進,旨在加速HTTP傳輸並使其更加安全,目標是想最終取代TCP和TLS協議。在本文中,我們將概述QUIC協議的一些關鍵特性和它們給Web帶來的好處,以及支持這一全新協議過程中遇到的一些挑戰。

讓互聯網更快:通往QUIC之路

實際上有兩個協議共享QUIC這個名稱,其一是“Google QUIC”(下稱“gQUIC”),是Google工程師幾年前設計的原始協議,經過多年的實驗,現已被IETF(Internet Engineering Task Force)採用並正在進行標準化。

另一個是“IETF QUIC”(下稱“QUIC”),由於和gQUIC有著顯著的差別,因此可以認為它是一個單獨的協議。通過許多組織和個人的協作努力,從數據傳輸格式到握手和HTTP映射,QUIC改進了原有的gQUIC設計,但共同目標仍然是儘可能讓互聯網變得更快、更安全。那麼,QUIC都提供了哪些改進呢?

內置的安全和性能機制

QUIC與現在常用的TCP相比,一個徹底的改變是它的設計目標:默認提供安全的傳輸協議。QUIC通過在傳輸層提供安全特性(如身份驗證和加密)來實現,而以往這些功能通常由更高層的協議(如TLS)處理。

最初的QUIC握手方式結合了TCP經典的三次握手與TLS 1.3對端點的認證以及加密參數的協商。對於熟悉TLS協議的人來說,QUIC其實是取代了TLS記錄協議,保留了TLS握手協議。

這不僅確保了連接始終被認證和加密,而且還使得初始連接建立更快:與TCP和TLS 1.3握手相結合所需的兩次往返相比,典型的QUIC握手只需要在客戶端和服務器之間完成一次往返。

讓互聯網更快:通往QUIC之路

讓互聯網更快:通往QUIC之路

不僅如此,QUIC還加密了可能被中間設備濫用而干擾連接的其它元數據。例如,當使用連接遷移時,被動式攻擊可以使用數據包序號來關聯多個網絡路徑上的用戶活動(見下文)。通過加密數據包序號,QUIC可以確保它們不能被連接端點之外的任何實體關聯活動。

加密也可以成為僵化問題(ossification)的有效補救措施,這使得協議的靈活性(例如能夠協商不同版本的協議)由於錯誤的假設而在實踐中不能被使用。僵化問題導致了TLS 1.3部署的長期延遲,而在幾次更改(防止中間設備錯誤地阻止新版本的TLS協議)被採用之後才使得部署變得可能。

隊頭阻塞

HTTP/2提供的重要改進之一是能夠將不同的HTTP請求複用同一個TCP連接,這使得HTTP/2應用程序可以並行處理請求並更好地利用可用的網絡帶寬。

這是一項重大改進,如果想要同時處理多個HTTP/1.1請求(例如當瀏覽器需要同時獲取CSS和JavaScript資源渲染網頁時),應用程序需要啟動多個TCP + TLS連接。創建新連接需要重複多次初始握手,以及初始擁塞窗口加速,這意味著網頁的渲染速度會降低,而多路複用HTTP則避免了這些問題。

讓互聯網更快:通往QUIC之路

然而,它也有一個缺陷,由於多個請求/響應使用相同的TCP連接傳輸,所以它們都受到數據包丟失的影響(例如由於網絡擁塞),即使丟失的數據僅涉及單個請求。這種現象被稱為“隊頭阻塞”。

QUIC更進一步為多路複用提供了良好的支持,使得不同的HTTP流可以依次映射到不同的QUIC傳輸流,但是它們仍然共享相同的QUIC連接,因此不需要進行額外的握手,並且共享擁塞狀態, QUIC流是獨立傳遞的,因此在大多數情況下,一個流的數據包丟失不會影響其它傳輸流。

這可以大大減少例如渲染完整網頁(包括CSS、JavaScript、圖片和其它類型資源)所需的時間,特別是在通過具有較高丟包率的高擁塞網絡時。

這很簡單,呃?

為了實現這些目標,QUIC協議需要打破許多網絡應用程序認為理所當然的一些假設,這可能使QUIC的實現和部署更加困難。

QUIC的設計基於UDP數據報來簡化部署,同時避免部分網絡設備丟棄未知協議數據包的問題,因為絕大多數設備已經支持UDP。這也允許了QUIC在用戶空間中實現,例如,瀏覽器能夠實現新的協議功能併發送給用戶,而無需等待操作系統更新。

然而,儘管預期的目標是避免破壞,但它仍在防止濫用並將數據包路由到正確的端點方面極具挑戰性。

通過一個NAT問題深入理解

典型的NAT路由器可以使用傳統的4元組(源IP地址和端口,目的IP地址和端口)跟蹤通過它們的TCP連接,並通過觀察傳輸的TCP SYN、ACK和FIN數據包,可以檢測到連接的建立和終止。這樣可以精確地管理NAT綁定的生命週期和內外部IP地址和端口的關聯關係。

但是這在QUIC還不能實現,因為目前部署的NAT路由器不瞭解QUIC,因此它們通常會回退到默認配置,然後對UDP流處理的不太準確,通常會使用任意的,有時非常短的超時,可能會影響長時間運行的連接。

當NAT重新綁定時(例如超時),NAT外部的端點將看到來自與最初建立連接時觀察到的源端口不同的數據包,這使得僅使用4元組無法跟蹤連接。

讓互聯網更快:通往QUIC之路

不僅僅是NAT!QUIC旨在提供的功能之一稱為“連接遷移”,允許QUIC端點隨意遷移到不同IP地址和網絡路徑的連接。例如,當已知的Wi-Fi網絡可用時(例如,當用戶進入他們喜歡的咖啡店時),移動客戶端能夠在蜂窩數據網絡和Wi-Fi之間遷移QUIC連接。

QUIC試圖通過引入連接ID的概念來解決這個問題:一個由QUIC數據包攜帶的可變長度的opaque blob,可用於標識連接。端點可以使用此ID來跟蹤它們負責的連接,而無需檢查4元組(實際上,可能有多個ID標識相同的連接,例如,為了避免在使用連接遷移時鏈接不同的路徑, 但這種行為是由端點而不是中間設備控制的)。

但是,這也給使用anycast尋址和ECMP路由的網絡運營商帶來了問題,其中單個目標IP地址可能潛在地識別數百甚至數千個服務器。由於這些網絡使用的邊緣路由器還不知道如何處理QUIC流量,因此可能會發生UDP數據包雖然屬於相同的QUIC連接(即具有相同的連接ID)但具有不同的4元組(由於 NAT重新綁定或連接遷移)被路由到不同的服務器,從而破壞了連接。

讓互聯網更快:通往QUIC之路

為了解決這個問題,網絡運營商可能需要採用更智能的4層負載均衡解決方案,它們可以通過軟件實現,而無需接觸邊緣路由器即可部署(參見Facebook的Katran項目)。

QPACK

HTTP/2帶來的另一個好處是頭部壓縮(header compression或HPACK),它允許HTTP/2端點通過從HTTP請求和響應中刪除冗餘來減少網絡傳輸的數據量。

特別是,在其它技術中,HPACK使用之前的HTTP請求(或響應)發送(或接收)的報頭動態填充表項,允許端點在新請求(或響應)中引用先前遇到的報頭,而不是再次傳輸。

HPACK的動態表需要在編碼器(發送HTTP請求或響應的一方)和解碼器(接收它們的一方)之間同步,否則解碼器將無法解碼它接收的內容。

對於TCP上的HTTP/2,這種同步是透明的,因為傳輸層(TCP)負責以與發送它們相同的順序提供HTTP請求和響應,更新表的指令可以簡單地由編碼器作為部分請求(或響應)本身,使得編碼非常簡單。但對於QUIC來說,這有些複雜。

QUIC可以獨立地在不同的流上處理多個HTTP請求(或響應),這意味著雖然就單個流而言它負責按順序交付數據,但是跨多個流是沒有順序保證的。

舉例來說,如果客戶端通過QUIC流A發送HTTP請求A,然後通過流B發送請求B,由於網絡中的數據包重新排序或丟失,可能會發生服務器在請求A之前接收到請求B,並且請求B被編碼引用了來自請求A的頭,那麼服務器將無法解碼它,因為它還沒有接收到請求A。

在gQUIC協議中,通過簡單地在同一gQUIC流上串行化所有HTTP請求和響應頭(不是body)來解決這個問題,這意味著無論如何都會按順序傳遞報頭。這是一個非常簡單的方案,可以實現重用大量現有的HTTP/2代碼,但另一方面它增加了QUIC期望減少的隊頭阻塞。因此,IETF QUIC工作組設計了一組HTTP和QUIC之間(“HTTP/QUIC”)的新映射關係,以及稱為“QPACK”的新報頭壓縮方案。

在HTTP/QUIC映射和QPACK規範的最新草案中,每個HTTP請求/響應交換使用自身的雙向QUIC流,因此沒有隊頭阻塞。此外,為了支持QPACK,每端需要額外創建兩個單向QUIC流,一個用於向另一個對等體發送QPACK表更新,另一個用於確認另一方接收的更新。這樣,QPACK編碼器只有在解碼器明確確認之後才能使用動態表引用。

應對反射攻擊

基於UDP的協議中的一個常見問題是它們容易受到反射攻擊,攻擊者通過源IP地址欺騙(它們看起來像是發送自受害者)誘使一些服務器向第三方受害者發送大量數據。

讓互聯網更快:通往QUIC之路

當服務器發送的響應大於收到的請求時,這種攻擊非常有效,這種情況我們稱為“放大”。

TCP通常不受這種攻擊影響,因為在握手期間發送的初始數據包(SYN,SYN+ACK,...)具有相同的長度,所以它們不具有任何放大的潛力。

另一方面,QUIC的握手是非常不對稱的:像TLS一樣,在第一次傳輸中,QUIC服務器通常發送自己的證書鏈,這可能非常大,而客戶端只需要發送幾個字節(QUIC包中嵌入的TLS ClientHello消息)。因此,客戶端發送的初始QUIC數據包必須填充到特定的最小長度(即使數據包的實際內容要小得多)。然而,這種緩解仍然不夠,因為常見的服務器響應會跨多個數據包,可能仍遠遠大於客戶端填充後的數據包。

QUIC協議還定義了一種顯式的源地址驗證機制,服務器先不發送長響應,而是僅發送一個小得多的retry數據包,其中包含一個唯一的加密令牌,然後客戶端必須在新的初始數據包中回應它。這樣,服務器就更方便確認客戶端不會進行源IP地址欺騙(因為它收到了retry數據包),並且可以完成握手。這種緩解方法的缺點是它將初始握手持續時間從單次往返增加到兩次。

另一種解決方案通過減少服務器響應降低反射攻擊效果,例如採用ECDSA證書(通常比RSA小很多)。此外,也可以嘗試通過現成的壓縮算法(如zlib和brotli)壓縮TLS證書,這也是gQUIC最初引入的特性,但目前在TLS中還不可用。

UDP性能

QUIC經常出現的問題之一是已經部署的硬件和軟件無法識別它。前面介紹了QUIC如何嘗試解決路由器等網絡中間設備問題,但另一個可能存在的問題是在QUIC端點上通過UDP發送和接收數據的性能。多年來,很多工作旨在優化TCP,包括在軟件(如操作系統)和硬件(如網絡接口)中構建卸載功能,但目前這些功能都不適用於UDP。

然而,QUIC具備這些功能只是時間問題。以最近在Linux上實現UDP通用分段卸載(Generic Segmentation Offloading)的工作為例,這將允許應用程序在用戶空間和內核空間網絡堆棧之間彙集和傳輸多個UDP段轉換為單個(或者近似)UDP段。此外,還有在Linux上添加zerocopy套接字支持的例子,這將使應用程序避免將用戶空間內存複製到內核空間。

結論

與HTTP/2和TLS 1.3一樣,QUIC將提供多項旨在提高網站性能和安全等方面的新功能,目前IETF工作組計劃在今年年底前提供QUIC規範的第一版。

原文鏈接:

https://blog.cloudflare.com/the-road-to-quic/


分享到:


相關文章: