迈向QUIC:HTTP / 3的基础

Internet历史上的一个新里程碑开始在我们眼前:我们可以假设HTTP / 3已经宣布。 10月底,IETF的Mark Nottingham 建议已经确定 IETF自2015年以来一直在其上建立的新协议的名称 。 因此,出现了响亮的HTTP / 3,而不是类似QUIC的名称。 西方出版物已经对此进行 了多次 写作 。 QUIC的历史始于2012年Good Company的兴起,此后只有Google的服务器支持HTTP-QUIC连接,但是随着时间的流逝,Facebook已经开始实施该技术(11月7日, FacebookLiteSpeed首次通过HTTP / 3进行了交互。 ); 目前,支持QUIC的网站所占比例为1.2%。 最后,WebRTC工作组也正在寻求QUIC (另请参见QUIC API ),因此在可预见的将来,实时视频/音频将通过QUIC而不是RTP / RTCP。 因此,我们认为最好公开IETF QUIC的详细信息:特别是针对Habr,我们准备了长期阅读的点i的译文。 好好享受

QUIC(快速UDP Internet连接)是一种新的加密默认传输层协议,具有许多HTTP增强功能:既可以加快通信速度,又可以提高安全性。 QUIC还有一个长期目标-最终取代TCP和TLS。 在本文中,我们将研究关键的QUIC芯片以及为什么Web将从中受益,以及支持这种全新协议的问题。

实际上,有两个名称相同的协议:Google QUIC(gQUIC),它是Google工程师几年前开发的原始协议,经过一系列实验,Internet工程任务组(IETF)对其进行了标准化。

IETF QUIC(以下简称QUIC)与gQUIC的区别已经很大,可以认为它是单独的协议。 从软件包格式到握手和HTTP映射,QUIC通过与许多组织和开发人员合作来改进了原始gQUIC体系结构,这些组织和开发人员的共同目标是:使Internet更快,更安全。

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

集成安全性(和性能)


QUIC和古老的TCP之间最明显的区别之一是最初提出的目标,即默认情况下安全的传输协议。 QUIC通过使用身份验证和加密来实现此目的,身份验证和加密通常发生在更高级别(例如,在TLS中),而不是在传输协议本身中。

原始的QUIC握手将基于TCP的常规三向通信与TLS 1.3握手相结合,从而提供了参与者的身份验证以及密码参数的协调。 对于熟悉TLS的用户:QUIC用其自己的帧格式替换TLS记录级别,但同时使用TLS握手。

这不仅允许始终对连接进行加密和认证,而且使建立初始连接的速度更快:普通的QUIC握手通过一次即可进行客户端和服务器之间的交换,而TCP + TLS 1.3进行两次通过。


但是,QUIC走得更远,还对连接元数据进行加密,而第三方很容易破坏这些元数据。 例如,当使用连接迁移时,攻击者可以使用数据包编号引导用户跨多个网络路径(请参阅下文)。 QUIC对数据包号进行加密,因此,除了连接的真正参与者之外,其他任何人都无法纠正它们。

加密还可以有效地防止“停滞”,这种现象由于实现中的错误假设而无法在实践中使用协议的灵活性(骨化-这就是为什么TLS 1.3长期存在的原因 。我们仅在进行了一些更改之后才发布了该协议)防止新的TLS修订的有害阻止)

阻塞队列的开始(行头阻塞)


HTTP / 2给我们带来的主要改进之一是能够在一个TCP连接中组合不同的HTTP请求。 这使HTTP / 2应用程序可以并行处理请求并更好地利用网络通道。

当然,这是向前迈出的重要一步。 因为早期的应用程序要同时处理多个HTTP请求(例如,当浏览器需要同时接收CSS和JavaScript来呈现页面时),如果它们想同时处理多个HTTP请求,则它们需要启动许多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外围之外的设备开始接收来自另一个源的数据包,这使得仅使用4个值的元组来维持连接是不可能的。


而且不只是NAT! QUIC的一项功能称为连接迁移,它允许设备自行决定将连接转移到其他IP地址/路径。 例如,移动客户端将能够将QUIC连接从移动网络传输到已知的WiFi网络(用户已进入喜欢的咖啡店等)。

QUIC尝试使用连接ID的概念来解决此问题:以QUIC数据包的形式发送的任意长度的信息,并允许识别连接。 端点设备可以使用此ID来跟踪其连接,而无需与元组协调。 实际上,应该有许多ID指示相同的连接,例如,以避免在迁移连接时连接不同的路径-因为整个过程仅由终端设备控制,而不由中间盒控制。

但是,使用任播和ECMP路由的电信运营商可能会遇到问题,其中一个IP可能会标识成百上千个服务器。 由于这些网络中的边界路由器尚不知道如何处理QUIC流量,因此可能发生以下情况:来自同一QUIC连接但具有不同元组的UDP数据包将发送到不同的服务器,这意味着断开连接。



为避免这种情况,操作员可能需要实施更智能的液位平衡器。 这可以通过编程实现,而不会影响边界路由器本身(例如,请参阅Facebook的Katran项目)。

Qpack


HTTP / 2的另一个有用功能是标头压缩(Header Compression,HPACK) ,它允许终端设备通过丢弃不必要的请求和响应来减小所发送数据的大小。

特别是,除其他技术外,HPACK使用动态表,其表头已从先前的HTTP请求/响应发送/接收,这使设备可以在新的请求/响应中引用以前遇到的头(而不是再次发送它们)。 。

HPACK表必须在编码器(发送请求/响应的一方)和解码器(接收方)之间同步,否则解码器根本无法解码接收到的内容。

对于基于TCP的HTTP / 2,这种同步是透明的,因为传输层(TCP)按照发送请求/响应的相同顺序传递请求/响应。 也就是说,您可以向解码器发送指令,以在简单的请求/响应中更新表。 但是使用QUIC,事情就复杂得多了。

QUIC可以同时在不同方向上传递多个HTTP请求/响应,这意味着QUIC保证一个方向上的传递顺序,而在多个方向上则没有这样的保证。

例如,如果客户端在QUIC流A中发送HTTP请求A,以及在流B中发送请求B,则由于数据包置换或网络丢失,服务器将在请求A之前接收请求B。并且如果请求B编码为如果在请求A的标头中指出,则服务器将无法解码请求B,因为尚未看到请求A。

gQUIC协议通过简单地使HTTP请求/响应的所有标头(而不是正文)在单个gQUIC流中顺序排列来解决此问题。 这样可以确保无论发生什么情况,所有标头的顺序都正确。 这是一个非常简单的方案,在它的帮助下,现有解决方案可以继续使用在HTTP / 2下经过优化的代码。 另一方面,这增加了阻塞队列开始的可能性,而QUIC旨在降低这种可能性。 因此,IETF QUIC工作组开发了HTTP和QUIC之间的新映射(HTTP / QUIC),以及新的报头压缩原理QPACK。

在HTTP / QUIC和QPACK规范的最终草案中,每个HTTP请求/响应交换都使用其自己的双向QUIC流,因此不会发生阻塞队列开始的情况。 同样,为了支持QPACK,每个参与者都创建了两个附加的单向QUIC流,一个流发送表更新,另一个流确认其接收。 因此,仅在解码器确认接收到QPACK编码器后,才能使用指向动态表的链接。

折射反射


基于UDP的协议的一个常见问题是,当攻击者强迫服务器向受害者发送大量数据时,它们容易受到反射攻击。 攻击者欺骗了他的IP,使服务器认为数据请求来自受害者的地址。


当服务器响应比请求大得多时,这种类型的攻击可能非常有效。 在这种情况下,他们说的是“收益”。

TCP通常不用于此类攻击,因为原始握手(SYN,SYN + ACK等)中的数据包具有相同的长度,因此它们没有“放大”的可能。

另一方面,QUIC握手非常不对称:与TLS中一样,首先,QUIC服务器发送其证书链,该证书链可能会很大,尽管客户端只发送几个字节(来自ClientHello TLS客户端的消息已内置在QUIC包中) ) 因此,即使包装中的物品小得多,原始QUIC包装也必须增加到一定的最小长度。 尽管如此,此措施仍然不是很有效,因为典型的服务器响应包含多个数据包,因此可能不仅仅是扩展的客户端程序包。

QUIC协议还定义了显式的源验证机制:服务器没有给出较大的响应,而是仅发送带有唯一令牌的重试数据包,然后客户端将其以新数据包的形式发送给服务器。 因此,服务器对客户端没有替代IP地址更有信心,您可以结束握手。 决定的减去-握手时间增加,而不是一遍,已经需要两遍了。

一种替代解决方案是将服务器响应减小到反射攻击变得不太有效的大小,例如,使用ECDSA证书 (通常比RSA小得多)。 我们还使用诸如zlib和brotli之类的现成压缩算法对TLS证书压缩机制进行了实验。 此功能最早出现在gQUIC中,但TLS当前不支持。

UDP性能


QUIC经常出现的问题之一是无法与QUIC一起使用的现有硬件和软件。 我们已经检查了QUIC如何尝试处理路由器等网络中间盒,但是另一个潜在的问题区域是QUIC设备之间通过UDP发送/接收数据的性能。 多年来,人们一直在努力尽可能地优化TCP实现,包括软件(例如,操作系统)和硬件(网络接口)中的内置卸载功能,但这与UDP无关。

但是,QUIC的实现超过这些改进和好处只是时间问题。 看看最近在Linux上实现UDP卸载的工作 ,这将使应用程序可以在用户空间和内核空间网络堆栈之间合并和传输多个UDP段,而代价约为一个段; 另一个示例是Linux对套接字的零拷贝支持,这使应用程序可以避免将用户空间内存复制到内核空间的开销。

结论


像HTTP / 2和TLS 1.3一样,QUIC协议应带来大量新功能,这些新功能将改善网站以及Internet基础结构中其他参与者的性能和安全性。 IETF工作组打算在今年年底之前推出QUIC规范的第一个版本,因此现在该考虑如何才能最大程度地利用QUIC的好处了。

Source: https://habr.com/ru/post/zh-CN430436/


All Articles