目录

基于UDP的新世界:QUIC、DNS、WebRTC

因为魔法软件的一些奇奇怪怪的问题,进而怀疑是 HTTP/3 搞得鬼,于是有了这篇文章,算是一个铺垫。

HTTP/3 是超文本传输协议 (HTTP) 的下一个主要版本。于 2021 年发布。

HTTP/3 的主要一个特点是它使用一种新的传输协议 QUIC 来运行。QUIC 旨在提供快速连接,支持迅速切换网络。

Tip

阅读本文可能需要具备了解 TCP / IP 协议、http 请求的整个过程相关基础知识。

QUIC(Quick UDP Internet Connections)由 Google 开发的一种基于 UDP 的传输层网络协议,旨在替代传统的 TCP 协议。

它集成了加密(类似 TLS),支持多路复用,可以快速恢复连接。

多路复用(Multiplexing)指的是在同一个连接(比如一个 QUIC 连接)上同时传输多个独立的数据流(streams),每个数据流可以独立发送和接收数据。

早在 HTTP/2 时代就在 TCP 之上实现了应用层的多路复用,但无法解决 TCP 层的队头阻塞。也就是逻辑上独立,但在传输层面共享同一个 TCP 的有序字节流。

在 QUIC 中,每个数据流都有一个唯一的流 ID。发送端将不同流的数据分成多个数据包,每个数据包带有流 ID 和偏移量(offset),接收端根据流 ID 和偏移量将数据重新组装。

这样,多个数据流的数据可以交错发送,而不会互相阻塞,再加上基于 UDP 在传输层彻底解决了队头阻塞问题。

经典的 http/2 模型中,可以简化为 http/2 –> TLS –> TCP –> IP;而到了 QUIC,基本就是保留 HTTP 的基本语义,但把 http/2 + TLS + TCP 的优点整合了起来,因为还得兼容目前的传输层协议(传输层由操作系统内核负责,搞出一个新协议让全球系统都更新那是不现实的),TCP 肯定不行(本来就是为了解决 TCP 的一些问题),那只能选 UDP 了,也就是 QUIC / HTTP/3 –> UDP(作为媒介) –> IP,QUIC 的大部分逻辑都是应用层实现的。

关于快速恢复连接,传统的 TCP 当 IP 发生变化时,例如从 WIFI 切换到数据流量,IP 变化需要重新进行 TCP 握手,到了 QUIC,里面会封装一个连接 ID,只要连接 ID 一样,就可以继续通信,不过这种修改对原有的负载均衡、防火墙等设施会是个不小的挑战,需要针对性做识别或者难以精准识别。

UDP 本身不保证可靠性,QUIC 在应用层实现了可靠传输机制。

队头阻塞是 TCP 和 HTTP/2 中的一个问题:在一个连接中,如果一个数据包丢失,后续所有数据包都必须等待该丢失包重传完成后才能被处理,导致延迟增加。

因为 TCP 是面向字节流的协议,数据包必须按顺序到达。一个包丢失,后续包即使到达也不能被处理,必须等待丢失包重传。

QUIC 在传输层支持多条独立的数据流,每条流的数据包独立编号。丢包只影响对应流的数据重传,其他流的数据可以继续传输和处理。这样,某个流的丢包不会阻塞其他流,极大减少了延迟。

QoS(服务质量)是网络运营商或网络设备用来管理和控制网络流量的一种技术。

通过 QoS,网络可以对不同类型的流量进行分类、优先级排序、带宽限制、延迟控制等。例如,语音通话、视频会议可能被设置为高优先级,网页浏览或文件下载可能被限制带宽。

QoS 机制通常基于协议类型、端口号、IP 地址、流量特征等信息来识别和管理流量。

QUIC 基于 UDP 协议,而 UDP 流量在很多网络环境中被视为“非连接型”或“高风险”流量。

传统网络设备和运营商习惯于对 TCP 流量进行优化和优先处理,而 UDP 流量可能被限制或降速。

QUIC 的加密和多路复用特性使得网络设备难以深度检测(Deep Packet Inspection,DPI)其具体内容和应用类型(防火墙:看不懂?丢了!)。

因此,某些网络运营商或企业网络会对 UDP 流量(包括 QUIC)施加限制,比如:

  • 限制 UDP 流量带宽。
  • 阻断或丢弃 UDP 包。
  • 降低 UDP 流量优先级。

具体表现就是在某些网络环境下,使用 QUIC 的应用(如基于 HTTP/3 的网页访问、Google 服务等)可能会遇到:

  • 连接建立变慢。
  • 传输速度下降。
  • 连接不稳定或频繁重连。

所以,用上了 QUIC 不一定就比 http/2 快,也可能会出现刚开始很快,后面被 QoS 后就丢包严重。

RTT(Round-Trip Time,往返时间)是指网络请求从发送端到达接收端并返回发送端所需的时间,通常以毫秒为单位;

而我们常用的 1 RTT (One Round-Trip Time) 代表的是一个数据包从发送方发出,到达接收方,然后接收方发送一个响应数据包,该响应数据包再回到发送方所经历的总时间。

简单来说,它是一个往返时间;我们 ping 的时候看到的 time 其实就是 1 RTT。

传统 TCP + TLS 的握手过程 (通常需要 2-3 RTT):

  • TCP 握手 (1 RTT):

    Client -> Server: SYN

    Server -> Client: SYN-ACK

    Client -> Server: ACK

    到这里,TCP 连接才建立好,耗时 1 RTT。

  • TLS 1.2 握手 (2 RTT):

    Client -> Server: ClientHello

    Server -> Client: ServerHello, Certificate, ServerKeyExchange, ServerHelloDone

    Client -> Server: ClientKeyExchange, ChangeCipherSpec, Finished

    Server -> Client: ChangeCipherSpec, Finished

    TLS 1.2 握手完成,耗时 2 RTT。

  • TLS 1.3 握手 (1 RTT):

    Client -> Server: ClientHello

    Server -> Client: ServerHello, EncryptedExtensions, Certificate, Finished

    TLS 1.3 握手完成,耗时 1 RTT。

总计:

使用 TLS 1.2: 1 RTT (TCP) + 2 RTT (TLS) = 3 RTT

使用 TLS 1.3: 1 RTT (TCP) + 1 RTT (TLS) = 2 RTT

在最好的情况下,传统的 Web 访问也需要 2 次往返才能开始发送加密的应用数据。

0-RTT 允许客户端在与服务器建立连接时,无需等待任何往返时间 (RTT) 就可以发送应用层数据。这意味着,在某些情况下,客户端可以在发送第一个数据包的同时,就将加密的应用数据发送出去,从而大大减少了连接建立的延迟。

也就是传统的 http/2 时,使用 tls 1.2 至少 3 RTT 才可以传输数据,使用 tls 1.3 至少 2 RTT,但是 QUIC 把 TLS 整合到 http 中,这样就成了 1 RTT(本质逻辑上还是 TCP + TLS,Client Hello 时已经一次性把加密所需要的信息全部传过去),如果之前建立过连接,那么就直接成了 0 RTT。

0-RTT 如何实现?

0-RTT 的实现依赖于客户端和服务器之间之前已经成功建立过一次 QUIC 连接。

  1. 首次连接 (1-RTT):

    客户端和服务器进行完整的 QUIC 握手。

    在握手过程中,服务器会向客户端发送一个 会话票据 (Session Ticket) 或 恢复令牌 (Resumption Token)。这个票据包含加密密钥(用于后续 0-RTT 连接)和服务器的传输参数等信息。

    客户端将这个会话票据安全地存储起来。

  2. 后续连接 (0-RTT):

    当客户端再次尝试连接到同一个服务器时,它会使用之前存储的会话票据中的密钥来预先加密应用层数据。

    客户端将这个预加密的应用数据,连同其初始的 QUIC 握手包(包含会话票据),在一个数据包中发送给服务器。

    服务器收到这个数据包后,会尝试使用会话票据中的密钥来解密应用数据。

    如果解密成功,服务器就可以立即处理这些应用数据,而无需等待客户端的进一步响应。

    同时,服务器会完成正常的 QUIC 握手,建立一个具有完美前向保密性 (Perfect Forward Secrecy) 的新会话,用于后续的数据传输。

尽管 0-RTT 带来了巨大的性能提升,但它也引入了一个重要的安全风险:重放攻击 (Replay Attack)。

重放攻击的风险: 由于客户端在服务器完全验证当前会话之前就发送了加密数据,攻击者可以截获这个 0-RTT 数据包,并在稍后将其重新发送给服务器。如果服务器没有适当的机制来检测和阻止重放,它可能会多次执行相同的操作(例如,重复处理一个订单,或者重复发送一个消息)。

QUIC 的常见缓解措施:

  • 服务器端重放检测: 服务器必须跟踪它已经处理过的 0-RTT 会话票据或令牌,以拒绝重复的 0-RTT 数据包。
  • 限制 0-RTT 数据: 建议只在 0-RTT 中发送幂等 (Idempotent) 的请求(例如,HTTP GET 请求)。对于非幂等操作(例如,HTTP POST 请求,创建订单),应避免在 0-RTT 中发送,或者服务器必须有严格的去重机制。
  • 有限的密钥寿命: 0-RTT 使用的密钥具有较短的有效期,以限制潜在的攻击窗口。
  • 不提供完美前向保密性: 0-RTT 数据本身不提供完美前向保密性。如果用于加密 0-RTT 数据的密钥被泄露,那么所有使用该密钥的 0-RTT 数据都可能被解密。然而,一旦 1-RTT 握手完成,后续的数据传输将使用新的密钥,并提供完美前向保密性。

DNS 是做什么的就不介绍了,它在网络中的地位一直是非常重要的,基于 DNS 的攻击也没停止过,也是泄露隐私的关键之一,要不然也不至于发展出现在的 DoH、DoT。

对于这部分,关注的问题主要是 DNS 污染和 DNS 劫持,这俩是什么东西我在八年前就写过一个简短的笔记

现在也对这俩有了一些新认识,DNS 污染可能主要还是因为合规问题,国内的 DNS 基本都存在,别管用什么 DoH,都一样,只是说第三方的 DNS 污染的要少一些,运营商会更激进,尤其是移动。毕竟这种效果好成本低,比 DPI 可要省时省力省心。

DNS 劫持一般只发生在运营商默认的 DNS,除了是为了给你套广告来获益(也有一部分是投放木马),另一种就是因为跨网跨省结算,ISP 可能会缓存一些网页,访问的时候给你看缓存的网页以此来节省流量,这个从反馈来说也是移动之前干的多,目前整体看很少。

我们都知道 DNS 是明文,并且还是 UDP,篡改或者监控起来很容易,为了解决这个问题,于是有了 DoH(DNS over HTTPS)和 DoT(DNS over TLS),它们都是用于加密 DNS 查询以提高隐私和安全性的技术,它们的主要区别在于封装方式:

DoH 将 DNS 查询封装在 HTTPS 流量中,使用端口 443,使其与普通网页流量难以区分;

DoT 使用专用 TLS 连接,在专用端口 853 上传输,虽然更易被网络管理员识别和阻断,但能直接提供 DNS 隐私保护。

还有一个不常用的是 DoH3,它是 DNS over HTTP/3 的简称,它是一种基于 HTTP/3 和QUIC 协议的加密 DNS(域名系统)解析方法,国内基本不可用,一个是 UDP 的问题一个是支持的公共 DNS 很少。

目前来看,DoH 更普及一些,虽然使用国外的 DoH 能获得更准确的结果,但是一来速度慢,一个是 CDN 效果会很差,因为 CDN 目前还是比较依赖 DNS 解析的。

Warning

这里还要提醒下,任何在国内公网搭建私有 DNS 都是违法的,真要自建,局域网搭建一个就行了或者买台国外的 VPS,切记不要在国内 VPS 上搭建,搞不好会被请喝茶。

既然都说到这里了,那不如也把 SNI 阻断也一起说了吧,这也是常见的一种污染策略;

和 DNS 一样,它也是明文传输,也存在隐私泄露问题,它本意是为了解决一个服务器部署了多个网站,用来确定客户端访问的是那个网站的,以此在建立 TLS 时传递对应的证书。

所以即使使用 https,中间人看不到你的数据内容,但是你访问了什么网站还是知道的,但是话又说回来,部分魔法协议也利用了这个特点,进行域前置,让防火墙误判从而逃过封杀,这个就不展开说了,效果也不是很稳定。

既然可以看到访问的域名,那么就可以针对性的进行阻断,这就是防火墙的 SNI 阻断功能,同样是性价比超高的方案。

为了解决 SNI 隐私泄露的问题,也诞生了一些技术:

很显然就是加密 SNI,它需要依赖 DNS,在 DNS 查询阶段就发送对应域名的证书/公钥,然后使用证书加密 SNI。这里的 DNS 也需要 DoH 来保证安全。

缺点就是它只加密 SNI,其实其他一些信息也又隐私泄露的问题,并且如果证书变更,DNS 也未必会及时更新。

Encrypted Client Hello,即加密整个 ServerHello,它同样使用 DoH 进行公钥分发,不过进行了改进,如果解密失败 ECH 服务器会重新给客户端一份公钥进行重试。

但是目前支持的网站并不多,它还是算非常新的技术。测试网站

PS:Mihomo 的配置中可以开启相关实验性选项

不过话说回来,如果真使用了 http/3 那么也不需要这些东西了,毕竟 QUIC 本身就是全加密的。

WebRTC 的全称是 Web Real-Time Communication,即 网页即时通信。

简单来说,它是一项开源技术,允许网页浏览器和移动应用之间,无需安装任何插件或软件,就能直接进行实时音视频通话和数据交换。

它解决一个核心问题:如何在 Web 上简单、高效地实现实时的点对点(Peer-to-Peer, P2P)通信。

  1. 无插件化 (Plugin-Free):这是它最大的革命性之处。在 WebRTC 出现之前,要在浏览器里实现视频通话,通常需要依赖 Flash、Silverlight 或其他第三方插件,用户体验差且有安全风险。WebRTC 是 W3C 和 IETF 的官方标准,内嵌在主流浏览器(Chrome, Firefox, Safari, Edge)中,开发者可以直接通过 JavaScript API 调用。

  2. 实时性 (Real-Time):专为低延迟通信设计。它使用 UDP 协议作为主要传输方式,最大限度地减少数据传输的延迟,这对于音视频通话、在线游戏等场景至关重要。

  3. 点对点通信 (Peer-to-Peer, P2P):在理想情况下,两个用户的浏览器一旦建立连接,音视频数据流会直接在它们之间传输,不经过服务器中转。这大大降低了服务器的带宽成本和负载,也进一步减少了延迟。参考 NAT 穿透,使用的 ICE 框架本质也是 STUN (打洞) 和 TURN(中转)

  4. 安全性高 (Secure):WebRTC 强制要求所有数据流都必须加密。它使用 SRTP (Secure Real-time Transport Protocol) 协议对音视频数据进行加密,使用 DTLS (Datagram Transport Layer Security) 对数据通道进行加密,确保了通信过程的私密性和安全性。

  5. 开源免费:由 Google 开源,并由各大浏览器厂商共同推进,任何人都可以免费使用它来构建应用。

记得之前在 GitHub 看到过一个挺火的基于 WebRTC 的项目,记不清是做远程控制还是类似 OBS 的直播来,确实是不错的场景。

如果你使用魔法软件,并且在意 DNS 泄露,那么 QUIC 和 WebRTC 都应该禁用。

可以查看 cloudflare 提供的实时概览界面:AdoptionAndUsage

目前 Cloudflare 和 Google 是主要的 QUIC / HTTP3 的推动者,例如 Chrome 就会积极的尝试使用 http/3,如果网站不支持或者当前环境不理想,基本都支持自动回退到 http/2。

但是由于国内复杂的网络环境,以及 ISP 对 QUIC 不太积极,加上刚结束优惠期,进入跨网结算,以及蠕虫病毒历史原因等,UDP 本来就被限制的非常严重,尤其是网络高峰期 + 跨省 + 跨网,有老哥直接测出百度都丢包 20%。

如果使用的是魔法软件,那么可能更雪上加霜,原因后面我会单独写在介绍魔法软件配置的博文中。