编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

让互联网更快:通往QUIC之路

wxchong 2024-06-11 09:55:36 开源技术 38 ℃ 0 评论

QUIC(Quick UDP Internet Connections)是一种默认加密的新互联网传输协议,它提供了多项改进,旨在加速HTTP传输并使其更加安全,目标是想最终取代TCP和TLS协议。在本文中,我们将概述QUIC协议的一些关键特性和它们给Web带来的好处,以及支持这一全新协议过程中遇到的一些挑战。

实际上有两个协议共享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可以确保它们不能被连接端点之外的任何实体关联活动。

加密也可以成为僵化问题(ossification)的有效补救措施,这使得协议的灵活性(例如能够协商不同版本的协议)由于错误的假设而在实践中不能被使用。僵化问题导致了TLS 1.3部署的长期延迟,而在几次更改(防止中间设备错误地阻止新版本的TLS协议)被采用之后才使得部署变得可能。

队头阻塞

HTTP/2提供的重要改进之一是能够将不同的HTTP请求复用同一个TCP连接,这使得HTTP/2应用程序可以并行处理请求并更好地利用可用的网络带宽。

这是一项重大改进,如果想要同时处理多个HTTP/1.1请求(例如当浏览器需要同时获取CSS和JavaScript资源渲染网页时),应用程序需要启动多个TCP + TLS连接。创建新连接需要重复多次初始握手,以及初始拥塞窗口加速,这意味着网页的渲染速度会降低,而多路复用HTTP则避免了这些问题。

然而,它也有一个缺陷,由于多个请求/响应使用相同的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元组无法跟踪连接。

不仅仅是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重新绑定或连接迁移)被路由到不同的服务器,从而破坏了连接。

为了解决这个问题,网络运营商可能需要采用更智能的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地址欺骗(它们看起来像是发送自受害者)诱使一些服务器向第三方受害者发送大量数据。

当服务器发送的响应大于收到的请求时,这种攻击非常有效,这种情况我们称为“放大”。

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/

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表