QUIC (Quick UDP Internet Connections) 是一种新的默认加密Internet传输协议,它提供了许多改进,旨在加速 HTTP 通信并使其更加安全,其目标是最终取代 web 上 的 TCP 和 TLS。在这篇博文中,我们将概述 QUIC 的一些关键特性,它们如何为 web 带来好处,以及支持这个新协议所面临的一些挑战。

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP

事实上,有两个协议同名:“Google QUIC”(简称 gQUIC),是Google工程师几年前设计的原始协议,经过多年的试验,现在已经被 IETF(互联网工程任务组)采用进行标准化。

“IETF-QUIC”(从现在起就是“QUIC”)已经与 gQUIC 有相当大的不同,因此可以将其视为一个单独的协议。从数据包的格式,到握手(handshake)和 HTTP 映射,QUIC 改进了最初的 gQUIC 设计,这得益于许多组织和个人的开放协作,共同的目标是使互联网更快、更安全。

那么,QUIC提供了哪些改进?

内置安全性(和性能)

QUIC 与现在受人尊敬的 TCP 的一个更根本的差别是,它的设计目标是提供一个默认安全的传输协议。QUIC 通过提供安全特性来实现这一点,比如身份验证和加密,这些特性通常由比传输协议本身更高层的协议(如TLS)处理。

QUIC 初始握手合并了 TCP 的典型三次握手和 TLS 1.3 握手,提供了端点的身份验证和密码参数的协商。对于那些熟悉 TLS 协议的人,QUIC 用自己的帧格式替换 TLS 记录层,同时保持相同的TLS握手消息。

这不仅可以确保连接始终经过身份验证和加密,而且还可以加快初始连接的建立:与 TCP 和 TLS 1.3 握手组合起来所需的 2次 RTT(round-trip) 相比,典型的 QUIC 握手只需在客户端和服务器之间进行1 次 RTT。

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP

但 QUIC 更进一步,它还加密了额外的连接元数据(metadata),这些元数据可能被中间设备(middle-boxes)滥用来干扰连接。例如,当使用连接迁移(connection migration)时,被动路径攻击者可使用数据包编号关联多个网络路径上的用户活动(见下文)。通过加密数据包编号,QUIC 确保除了连接中的端点之外,任何人都不能使用它们来关联用户的活动。

加密也可以是对僵化(ossification)的一种有效的补救措施,它使得协议中内置的灵活性(例如能够协商(negotiate)该协议的不同版本)。由于实现中的错误假设而无法在实践中使用(僵化(ossification)是导致 TLS 1.3 长时间无法部署的原因,这只有在几次修改后才可能实现,这些修改旨在防止僵化的中间设备(middle-boxes)错误地阻塞 TLS 协议的新修订)。

队头阻塞(Head-of-line blocking)

HTTP/2 的主要改进之一是能够将不同的 HTTP 请求多路复用(multiplexing)到同一个TCP连接上。这允许 HTTP/2 应用程序并发地处理请求,并更好地利用可用的网络带宽。

与当时的现状相比,这是一个很大的改进,即如果应用程序希望同时处理多个 HTTP/1.1 请求,则需要启动多个 TCP+TLS 连接(例如,当浏览器需要同时获取 CSS 和 Javascript 资源来呈现网页时)。初始的握手会减慢初始页面的传输速度,这意味着需要多次刷新新页面。多路复用(Multiplexing)HTTP 避免了所有这些问题。

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP

然而,这也有一个缺点:由于多个请求/响应是通过同一个 TCP 连接传输的,因此它们都会受到数据包丢失(例如,由于网络拥塞)的影响,即使丢失的数据只涉及单个请求。这被称为“队头阻塞”(head-of-line blocking)。

QUIC 更深入一点,为多路复用提供一流的支持,这样不同的 HTTP 流可以映射到不同的 QUIC 传输流,但是它们仍然共享相同的 QUIC 连接,因此不需要额外的握手和共享拥塞状态。但是 QUIC流是独立的,这样在大多数情况下,一个流的包丢失不会影响其他流。

例如,这可以显著减少呈现完整网页(使用CSS、Javascript、图片和其他类型的资源)所需的时间,尤其是在穿越高度拥挤的网络、具有高数据包丢失率的网络时。

这么简单,呃?

为了实现它的承诺,QUIC 协议需要打破许多网络应用程序认为理所当然的一些假设,这可能会使QUIC 的实现和部署更加困难。

QUIC 被设计在 UDP 数据报之上传输,以便于部署,并避免网络设备丢弃未知协议的数据包,因为大多数设备已经支持UDP。这也允许 QUIC 实现在用户态(user-space)中生存,因此,例如浏览器将能够实现新的协议特性并将其发送给用户,而不必等待操作系统的更新。(而 TCP 协议的更新受到网络设备和操作系统内容的约束,这也是 QUIC 设计在 UDP 之上的原因之一)

然而,尽管预期的目标是避免破坏,但它也使得防止滥用和正确地将数据包路由到正确的端点更具挑战性。

一个 NAT 把他们都带来,在黑暗中捆绑他们(One NAT to bring them all and in the darkness bind them)

典型的 NAT 路由器可以使用传统的4元组(源 IP 地址和端口、目的 IP 地址和端口)来跟踪经过它们的TCP连接,并通过观察在网络上传输的 TCP SYN、ACK 和 FIN 包,来检测新连接何时建立和何时终止。这使它们能够精确地管理 NAT 绑定的生命周期(lifetime),内部 IP 地址和端口之间的关联,以及外部 IP 地址和端口之间的关联。

对于QUIC,这还不可能,因为现在广泛部署的 NAT 路由器还不了解 QUIC,所以它们通常会退回(fallback)到默认和不太精确的处理 UDP 流,这通常涉及使用任意的,有时非常短的超时,这可能会影响长时间运行的连接。

当 NAT 重新绑定发生时(例如由于超时),NAT 外围外部的端点将看到来自不同源端口的数据包,而不是最初建立连接时观察到的源端口,这使得仅使用4元组无法跟踪连接。

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP

不仅仅是 NAT!QUIC 打算提供的特性之一称为“连接迁移”(connection migration),它允许 QUIC 端点随意将连接迁移到不同的IP地址和网络路径。例如,当已知的 WiFi 网络可用时(比如当用户进入他们最喜欢的咖啡店时),移动客户端将能够在蜂窝数据网络和 WiFi 之间迁移 QUIC 连接。

QUIC 试图通过引入连接ID(connection ID)的概念来解决这个问题:一个由 QUIC 包携带的可变长度的不透明blob,可以用来标识连接。端点可以使用这个 ID 来跟踪它们负责的连接,而不需要检查4元组(实际上,同一个连接可能有多个 ID 标识,例如,在使用连接迁移(connection migration)时,为了避免链接不同的路径,但是这种行为由端点控制而不是中间设备控制)。

然而,这也给使用选播(anycast)寻址和 ECMP 路由的网络运营商带来了一个问题,在这些网络运营商中,一个目的地IP地址可能识别数百甚至数千个服务器。由于这些网络使用的边缘路由器还不知道如何处理 QUIC 流量,因此可能会发生属于同一 QUIC 连接(即具有相同连接ID)但具有不同4元组(由于 NAT 重新绑定或连接迁移)的UDP数据包可能最终被路由到不同的服务器,从而中断了连接。

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP

为了解决这一问题,网络运营商可能需要采用更智能的第4层负载平衡解决方案,这种解决方案可以在软件中实现,并且无需接触边缘路由器即可部署(例如,Facebook 的 Katran 项目)。

QPACK

HTTP/2 引入的另一个好处是头部压缩(或HPACK),它允许 HTTP/2 端点通过删除 HTTP 请求和响应中的冗余来减少通过网络传输的数据量。

特别是,在其他技术中,HPACK 使用动态表填充了从以前的 HTTP 请求(或响应)发送(或接收)的头,允许端点在新的请求(或响应)中引用以前遇到的头,而不必重新传输它们。

HPACK 的动态表需要在编码器 encoder(发送HTTP请求或响应的一方)和解码器 decoder(接收它们的一方)之间同步,否则解码器 decoder 将无法解码它接收到的内容。

对于 TCP 之上的 HTTP/2,这种同步是透明的,因为传输层(TCP)负责以相同顺序发送 HTTP 请求和响应,更新表的指令可以由编码器 encoder 作为请求(或响应)本身的一部分发送,从而使编码非常简单。但对 QUIC 来说,这更复杂。

QUIC 可以在不同的流上独立地传递多个 HTTP 请求(或响应),这意味着,尽管它负责按单流的顺序传递数据,但在多个流之间不能保证排序。

例如,如果客户端通过 QUIC stream A 发送 HTTP 请求 A,而通过 stream B 发送请求 B,则由于网络中的数据包重新排序或丢失,服务器可能会在请求A 之前接收到请求 B,并且如果请求 B 被用来自请求 A 的报头编码,服务器将无法解码,因为它还没有看到请求 A。

在 gQUIC 协议中,这个问题只需在同一个 gQUIC 流上序列化所有 HTTP 请求和响应头(而不是主体),这意味着无论发生什么,消息头都将按顺序传递。这是一个非常简单的方案,它允许实现(implementations)重用大量现有的 HTTP/2 代码,但另一方面,它增加了QUIC 原本设计减少的队头阻塞( head-of-line blocking )。IETF QUIC 工作组因此设计了 HTTP 和 QUIC 之间的新映射(“HTTP/QUIC”),以及一种称为“QPACK”的头压缩新方案。

在 HTTP/QUIC 映射和 QPACK 规范的最新草案中,每个 HTTP 请求/响应交换都使用自己的双向 QUIC 流,因此没有队头阻塞(head-of-line blocking)。另外,为了支持 QPACK,每个 peer 方创建两个e额外的单向 QUIC 流,一个用于向另一个 peer 方发送 QPACK 表更新,另一个用于确认另一方接收到的更新。这样,QPACK 编码器 encoder 只有在解码器 decoder 显式地确认了动态表引用之后才能使用它。

偏转反射(Deflecting Reflection)

基于UDP的协议中的一个常见问题是它们容易受到反射攻击(reflection attacks),即攻击者通过欺骗数据包的源 IP 地址,使其看起来像是来自受害者,从而欺骗原本无辜的服务器向第三方受害者发送大量数据。

(译)Cloudflare: 通往 QUIC 之路(The Road to QUIC)-LMLPHP
当服务器发送的响应恰好大于它接收到的请求时,这种攻击非常有效,在这种情况下,我们称之为“放大”。

TCP 通常不用于此类攻击,因为在其握手 (SYN, SYN+ACK, …) 过程中传输的初始数据包具有相同的长度,因此它们不会提供任何潜在放大攻击的风险。

另一方面,QUIC 的握手是非常不对称的:就像 TLS 一样,在它的第一次传输中,QUIC 服务器通常发送自己的证书链(certificate chain),它可能非常大,而客户端只需发送几个字节(TLS ClientHello消息嵌入 QUIC 包中)。因此,客户端发送的初始 QUIC 包必须填充到特定的最小长度(即使包的实际内容要小得多)。然而,这种缓解仍然不够,因为典型的服务器响应跨越多个数据包,因此仍然可以远远大于填充的客户端数据包。

QUIC协议还定义了一个显式的源地址验证(source-address verification)机制,在该机制中,服务器不发送长响应,只发送一个很小的“重试(retry)”包,其中包含一个唯一的加密令牌,然后客户端必须在新的初始包中向服务器回显。这样,服务器就有了更高的信心,即客户机不会欺骗自己的源IP地址(因为它收到了重试数据包(retry packet)),并且可以完成握手。这种缓解的缺点是,它将初始握手持续时间从 1 次 RTT 增加到 2 次。

另一种解决方案包括减少服务器对反射攻击(reflection attack)变得不那么有效的响应,例如使用 ECDSA 证书(通常比 RSA 证书小得多)。我们还一直在尝试使用现成的压缩算法(如 zlib 和 brotli)压缩 TLS 证书的机制,这是 gQUIC 最初引入的一个特性,但目前在 TLS 中还没有。

UDP 性能

QUIC 经常出现的一个问题是现在广泛部署的硬件和软件无法理解它。我们已经在另一个C端的路由器上测试了数据的传输性能。我们已经了解了 QUIC 如何尝试处理像路由器这样的网络中间设备,但是另一个潜在的问题是在 QUIC 端点上通过 UDP 发送和接收数据的性能。多年来,人们做了大量的工作来尽可能地优化 TCP 的实现,包括在软件(如操作系统)和硬件(如网络接口)中构建卸载功能,但目前还没有一种方法可用于UDP。

然而,等QUIC实现时也能利用这些功能,这只是时间问题。例如,最近在Linux上实现UDP通用分段卸载的工作,它允许应用程序以单个UDP段(或足够接近)的代价在用户态(user-space)和内核态(kernel-space)网络堆栈之间捆绑和传输多个 UDP 段,除了在Linux上添加零拷贝套接字支持之外,还允许应用程序避免将用户态(user-space )内存复制到内核空间的成本。

结论

与 HTTP/2 和 TLS 1.3一样,QUIC 将提供许多新特性,这些特性旨在提高web站点的性能和安全性,以及其他基于Internet的资产。IETF 工作组目前正准备在今年年底发布QUIC规范的第一版,Cloudflare的工程师们已经在努力工作,为我们所有的客户提供 QUIC 的好处。

04-17 23:13