QUIC
QUIC 은 두 끝점이 연결을 맺고 데이터를 주고받는 순서 규칙입니다. 연결을 여는 인사와 암호 열쇠를 맞추는 인사를 한 묶음으로 처리합니다. 오가는 데이터는 스트림이라는 여러 갈래로 나뉘어 흐릅니다. 패킷은 거의 전부가 암호화된 채로 나갑니다.
상세
QUIC 은 범용 보안 전송 프로토콜입니다. RFC 9000 이 QUIC 판 1을 정의합니다. 클라이언트와 서버 사이에 상태를 가진 상호작용을 만드는 연결 지향 프로토콜입니다. QUIC 패킷은 UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜) 데이터그램에 실려 갑니다. RFC 9000 은 그렇게 한 이유를 기존 시스템과 네트워크에 배치하기 쉽게 하려는 것이라고 적습니다.
끝점끼리는 QUIC 패킷을 주고받으며 통신합니다. 대부분의 패킷은 프레임을 담습니다. 프레임이 제어 정보와 애플리케이션 데이터를 끝점 사이에 나릅니다. QUIC 은 패킷 하나하나를 통째로 인증하고, 실용적인 한도까지 최대한 많은 부분을 암호화합니다.
스트림
애플리케이션 프로토콜은 스트림을 통해 QUIC 연결 위에서 정보를 주고받습니다. 스트림은 순서가 있는 바이트 열입니다. 스트림은 단방향일 수도 있고 양방향일 수도 있습니다. 단방향 스트림은 스트림을 연 쪽에서 상대 쪽으로 한 방향으로만 데이터를 나릅니다. 양방향 스트림은 양쪽 다 데이터를 보냅니다. 스트림 생성과 보낼 수 있는 데이터 양은 크레딧 기반 방식이 묶습니다.
스트림은 데이터를 보내는 것만으로 만들어집니다. STREAM 프레임 하나가 스트림을 열고, 데이터를 싣고, 닫는 일까지 할 수 있습니다. 연결이 사는 내내 유지되는 스트림도 있습니다. 스트림은 어느 끝점이든 만들 수 있고, 다른 스트림과 뒤섞여 동시에 데이터를 보낼 수 있고, 취소될 수 있습니다. 서로 다른 스트림에 실린 바이트 사이의 순서는 QUIC 이 보장하지 않습니다.
스트림은 연결 안에서 스트림 ID 라는 숫자 값으로 식별됩니다. 스트림 ID 는 62비트 정수이고 한 연결의 모든 스트림에서 유일합니다. 끝점은 한 연결 안에서 스트림 ID 를 재사용해서는 안 됩니다. 가장 낮은 비트가 스트림을 연 쪽을 가리키고, 그다음으로 낮은 비트가 양방향인지 단방향인지를 가릅니다.
| 두 하위 비트 | 스트림 종류 |
|---|---|
| 0x00 | 클라이언트가 연 양방향 스트림 |
| 0x01 | 서버가 연 양방향 스트림 |
| 0x02 | 클라이언트가 연 단방향 스트림 |
| 0x03 | 서버가 연 단방향 스트림 |
연결과 연결 ID
QUIC 연결은 클라이언트와 서버가 나눠 가진 상태입니다. 연결은 핸드셰이크 단계로 시작합니다. 그 단계에서 두 끝점이 암호 핸드셰이크 프로토콜로 공유 비밀을 세우고 애플리케이션 프로토콜을 협상합니다. 핸드셰이크는 양쪽이 통신할 뜻이 있음을 확인하고 연결 파라미터를 세웁니다.
애플리케이션 프로토콜은 핸드셰이크 단계에서도 제한을 안고 연결을 쓸 수 있습니다. RTT(Round-Trip Time, 왕복 시간)는 한 번 오갔다 돌아오는 것을 세는 단위입니다. 0-RTT 는 서버의 응답을 받기 전에 클라이언트가 애플리케이션 데이터를 보내게 해 줍니다. 다만 0-RTT 는 재생 공격을 막아 주지 않습니다. 서버 쪽도 클라이언트의 신원과 생존을 확인할 마지막 암호 핸드셰이크 메시지를 받기 전에 애플리케이션 데이터를 보낼 수 있습니다. 이런 능력 덕분에 애플리케이션 프로토콜은 보안 보장 일부를 지연과 맞바꾸는 선택지를 내놓을 수 있습니다.
QUIC 연결은 하나의 네트워크 경로에 단단히 묶이지 않습니다. 연결 마이그레이션은 연결 식별자를 써서 연결을 새 네트워크 경로로 옮깁니다. 이 판의 QUIC 에서는 클라이언트만 마이그레이션할 수 있습니다. 이 설계 덕분에 NAT(Network Address Translation, 네트워크 주소 변환) 재바인딩처럼 네트워크 구성이나 주소 매핑이 바뀐 뒤에도 연결이 이어질 수 있습니다.
연결마다 연결 ID 묶음을 가집니다. 연결 ID 는 각 끝점이 따로 고릅니다. 각 끝점이 고르는 것은 상대가 쓸 연결 ID 입니다. 연결 ID 의 주된 기능은 UDP 나 IP(Internet Protocol, 인터넷 프로토콜) 같은 하위 프로토콜 계층에서 주소가 바뀌어도 그 연결의 패킷이 엉뚱한 끝점으로 배달되지 않게 하는 것입니다. 연결 ID 를 여럿 두는 이유는, 끝점이 협조하지 않는 한 관찰자가 여러 패킷을 같은 연결의 것으로 알아보지 못하게 하려는 것입니다. 그래서 연결 ID 는 외부 관찰자가 같은 연결의 다른 연결 ID 와 엮는 데 쓸 수 있는 정보를 담아서는 안 됩니다. 같은 연결 ID 를 한 연결에서 두 번 발급하면 안 된다는 것이 그 가장 단순한 사례입니다. 긴 헤더를 쓰는 패킷에는 Source Connection ID 와 Destination Connection ID 필드가 들어갑니다.
TLS 와의 관계
QUIC 은 패킷의 기밀성과 무결성 보호를 스스로 떠맡습니다. 그 열쇠는 TLS(Transport Layer Security, 전송 계층 보안) 핸드셰이크에서 나옵니다. TCP(Transmission Control Protocol, 전송 제어 프로토콜) 위에서 TLS 를 쓸 때와 달리, TLS 레코드를 QUIC 으로 나르지 않습니다. TLS 핸드셰이크 메시지와 alert 메시지가 QUIC 전송 위에 바로 실립니다. QUIC 전송이 TLS 레코드 계층의 책임을 넘겨받습니다. QUIC 은 보안과 성능에 중요한 파라미터의 인증과 협상도 TLS 에 기댑니다.
두 프로토콜은 엄격하게 층으로 나뉘지 않고 협력합니다. QUIC 은 TLS 핸드셰이크를 쓰고, TLS 는 QUIC 이 주는 신뢰성과 순서 있는 전달, 레코드 계층을 씁니다. TLS 쪽은 QUIC 을 통해 메시지를 보내고 받습니다. 그 반대 방향으로 TLS 는 QUIC 에 설치할 새 패킷 보호 키와 핸드셰이크 완료·서버 인증서 같은 상태 변화를 계속 알려 줍니다.
QUIC 은 신뢰성 있는 전달과 혼잡 제어를 구현하는 데 필요한 피드백을 줍니다. 데이터 손실을 감지하고 복구하는 알고리즘, 그리고 본보기가 되는 혼잡 제어 알고리즘은 RFC 9002 가 따로 적습니다.
핸드셰이크는 애플리케이션 데이터를 되도록 이른 시점에 주고받을 수 있는 구조입니다. 클라이언트가 데이터를 곧바로 보내는 선택지도 여기 들어 있습니다. 그것이 0-RTT 이고, 쓰려면 앞선 통신이나 설정이 어떤 형태로든 있어야 합니다.
교환 순서
QUIC 은 연결 수립 지연을 줄이려고 암호 핸드셰이크와 전송 핸드셰이크를 하나로 묶습니다. 암호 핸드셰이크는 CRYPTO 프레임에 실려 갑니다. RFC 9000 이 정의하는 판은 0x00000001 로 식별되고 TLS 를 씁니다. 다른 QUIC 판은 다른 암호 핸드셰이크 프로토콜을 쓴다고 알릴 수도 있습니다. QUIC 은 암호 핸드셰이크 데이터를 신뢰성 있게, 순서를 지켜 전달합니다. 핸드셰이크 프로토콜 자체도 가능한 한 패킷 보호로 암호화됩니다.
암호 핸드셰이크가 반드시 제공해야 하는 성질은 셋입니다.
| 성질 | 내용 |
|---|---|
| 인증된 키 교환 | 서버는 언제나 인증되고 클라이언트는 선택적으로 인증된다. 연결마다 서로 무관한 별개의 키가 나오고, 그 키 재료는 0-RTT 패킷과 1-RTT 패킷 보호에 쓸 수 있어야 한다 |
| 전송 파라미터의 인증된 교환 | 양쪽 끝점의 전송 파라미터를 인증된 상태로 주고받는다. 서버 전송 파라미터에는 기밀성 보호가 붙는다 |
| 애플리케이션 프로토콜의 인증된 협상 | TLS 는 이 목적에 ALPN(Application-Layer Protocol Negotiation, 응용 계층 프로토콜 협상)을 쓴다 |
CRYPTO 프레임은 서로 다른 패킷 번호 공간에서 보낼 수 있습니다. 암호 핸드셰이크 데이터의 순서를 지키려고 CRYPTO 프레임이 쓰는 오프셋은 패킷 번호 공간마다 0에서 시작합니다.
1-RTT 핸드셰이크 한 벌
RFC 9000 이 싣는 1-RTT 핸드셰이크 예시입니다. 각 줄이 QUIC 패킷 하나이고, 패킷 종류와 패킷 번호가 먼저 오고 그 뒤에 그 패킷에 흔히 담기는 프레임이 옵니다. 첫 패킷은 Initial 종류이고 패킷 번호가 0이며 ClientHello 를 나르는 CRYPTO 프레임을 담습니다.
sequenceDiagram
participant 클라이언트
participant 서버
클라이언트->>서버: Initial[0]: CRYPTO[CH]
서버-->>클라이언트: Initial[0]: CRYPTO[SH] ACK[0]<br/>Handshake[0]: CRYPTO[EE, CERT, CV, FIN]<br/>1-RTT[0]: STREAM[1]
클라이언트->>서버: Initial[1]: ACK[0]<br/>Handshake[0]: CRYPTO[FIN], ACK[0]<br/>1-RTT[0]: STREAM[0], ACK[0]
서버-->>클라이언트: Handshake[1]: ACK[0]<br/>1-RTT[1]: HANDSHAKE_DONE, STREAM[3]
클라이언트가 Initial 패킷에 ClientHello 를 담아 보냅니다. 서버는 CRYPTO[SH] 를 담은 Initial 패킷과 CRYPTO[EE, CERT, CV, FIN] 을 담은 Handshake 패킷으로 답합니다. 이때 1-RTT 패킷에 실은 애플리케이션 데이터가 함께 나갈 수 있습니다. 클라이언트는 자기 Handshake 패킷에 CRYPTO[FIN] 을 담아 보내고 1-RTT 패킷으로 데이터를 보내기 시작합니다. 서버가 HANDSHAKE_DONE 프레임을 보내면서 핸드셰이크가 마무리됩니다. 그 뒤로 양쪽은 1-RTT 패킷으로 자유롭게 애플리케이션 데이터를 주고받습니다.
종류가 다른 QUIC 패킷도 UDP 데이터그램 하나에 합쳐 실을 수 있습니다. 그래서 이 핸드셰이크는 UDP 데이터그램 네 개만으로 이루어질 수도 있고, 그보다 많은 수가 될 수도 있습니다. 혼잡 제어나 증폭 방지처럼 프로토콜에 딸린 한도가 그 수를 좌우합니다. 서버의 첫 비행에는 Initial 패킷과 Handshake 패킷, 그리고 1-RTT 패킷에 실린 0.5-RTT 데이터가 들어갑니다.
암호화 수준과 패킷 번호 공간
QUIC 은 TLS 핸드셰이크 데이터를 CRYPTO 프레임에 담아 나릅니다. CRYPTO 프레임 하나는 오프셋과 길이로 식별되는 연속된 핸드셰이크 데이터 덩이입니다. 그 프레임은 QUIC 패킷으로 포장되어 현재 암호화 수준으로 암호화됩니다. TLS 가 만들어 낸 각 덩이는 그때 TLS 가 쓰던 키 묶음과 짝지어집니다. QUIC 이 그 데이터를 재전송해야 하면 TLS 가 이미 새 키로 넘어갔더라도 같은 키를 써야 합니다.
암호화 수준 하나가 패킷 번호 공간 하나에 대응합니다. 어느 패킷 번호 공간을 쓰는지가 프레임의 의미를 정하고, 어떤 프레임은 특정 패킷 번호 공간에서 금지됩니다. 패킷은 선로에서 순서가 뒤집힐 수 있으므로, QUIC 은 어떤 키가 그 패킷을 보호했는지를 패킷 종류로 알립니다. 종류가 다른 패킷들을 보낼 때 끝점은 그것들을 한 UDP 데이터그램에 합쳐 보내는 편이 좋습니다.
| 패킷 종류 | 암호화 키 | 패킷 번호 공간 |
|---|---|---|
| Initial | Initial secrets | Initial |
| 0-RTT Protected | 0-RTT | Application data |
| Handshake | Handshake | Handshake |
| Retry | Retry | N/A |
| Version Negotiation | N/A | N/A |
| Short Header | 1-RTT | Application data |
어느 암호화 수준의 키를 읽거나 쓸 수 있게 되면 TLS 가 그 사실을 QUIC 에 알립니다. 새 키는 언제나 TLS 에 입력을 넣은 결과로 생깁니다. TLS 는 클라이언트가 초기화했거나 새 핸드셰이크 데이터를 받았을 때만 새 키를 내놓습니다. 다만 TLS 구현이 처리 일부를 비동기로 할 수도 있습니다. 인증서를 검증하는 과정이 시간을 잡아먹는 대표적인 자리입니다. TLS 처리를 기다리는 동안 끝점은 아직 없는 키로 처리될 수도 있는 패킷을 버퍼에 담아 두는 편이 좋습니다. 새 암호화 수준이 열릴 때 TLS 가 QUIC 에 넘기는 것은 셋입니다. 비밀 하나, AEAD(Authenticated Encryption with Associated Data, 연관 데이터가 있는 인증 암호) 함수, KDF(Key Derivation Function, 키 유도 함수)입니다.
0-RTT 핸드셰이크 한 벌
0-RTT 는 핸드셰이크가 끝나기 전에 클라이언트가 애플리케이션 데이터를 보내게 하는 기능입니다. 앞선 연결에서 협상한 파라미터를 다시 쓰는 것이 그 바탕입니다. 그러려면 클라이언트가 중요한 파라미터를 기억하고 있어야 하고, 서버는 같은 정보를 되찾게 해 주는 TLS 세션 티켓을 받아야 합니다. 0-RTT 를 세우는 데 쓰이는 정보는 전부 같은 연결에서 나와야 합니다. TLS 1.3 은 원래 연결과 0-RTT 시도 사이의 시간에 7일 한도를 둡니다. 재생 공격에 노출될 수 있다는 점 때문에 생기는 제약도 따로 있습니다.
sequenceDiagram
participant 클라이언트
participant 서버
클라이언트->>서버: Initial[0]: CRYPTO[CH]<br/>0-RTT[0]: STREAM[0]
서버-->>클라이언트: Initial[0]: CRYPTO[SH] ACK[0]<br/>Handshake[0] CRYPTO[EE, FIN]<br/>1-RTT[0]: STREAM[1] ACK[0]
클라이언트->>서버: Initial[1]: ACK[0]<br/>Handshake[0]: CRYPTO[FIN], ACK[0]<br/>1-RTT[1]: STREAM[0] ACK[0]
서버-->>클라이언트: Handshake[1]: ACK[0]<br/>1-RTT[1]: HANDSHAKE_DONE, STREAM[3], ACK[1]
서버는 0-RTT 데이터를 1-RTT 패킷으로 확인 응답합니다. 클라이언트도 같은 패킷 번호 공간에서 1-RTT 패킷을 보냅니다. QUIC 은 TLS 의 early data 를 쓰지 않고 0-RTT 패킷으로 이른 데이터를 나릅니다. 그래서 NewSessionTicket 메시지의 max_early_data_size 파라미터를 다른 용도로 돌려 씁니다. 서버가 QUIC 0-RTT 데이터를 받아들일 뜻이 있으면 그 자리에 0xffffffff 라는 보초 값을 넣습니다. 받아들이지 않으면 NewSessionTicket 에서 early_data 확장을 아예 뺍니다.
예시
RFC 9001 부록이 실제 핸드셰이크 한 벌의 바이트를 싣습니다. 클라이언트가 고른 연결 ID 는
0x8394c8f03e515708 입니다.
클라이언트 Initial 패킷
클라이언트가 Initial 패킷을 보냅니다. 이 패킷의 보호되지 않은 페이로드에는 아래 CRYPTO 프레임이 들어 있고, 페이로드를 1162바이트로 채우기에 충분한 PADDING 프레임이 함께 들어갑니다.
060040f1010000ed0303ebf8fa56f129
39b9584a3896472ec40bb863cfd3e868
04fe3a47f06a2b69484c000004130113
02010000c000000010000e00000b6578
616d706c652e636f6dff01000100000a
00080006001d00170018001000070005
04616c706e0005000501000000000033
00260024001d00209370b2c9caa47fba
baf4559fedba753de171fa71f50f1ce1
5d43e994ec74d748002b000302030400
0d0010000e0403050306030203080408
050806002d00020101001c0002400100
3900320408ffffffffffffffff050480
00ffff07048000ffff08011001048000
75300901100f088394c8f03e51570806
048000ffff
보호되지 않은 헤더는 길이를 1182바이트로 적습니다. 4바이트 패킷 번호, 1162바이트의 프레임, 16바이트 인증 태그를 합한 값입니다. 헤더에는 연결 ID 와 패킷 번호 2가 들어 있습니다.
c300000001088394c8f03e5157080000449e00000002
페이로드를 보호하면 그 결과에서 헤더 보호용 표본을 뽑습니다. 헤더가 4바이트 패킷 번호 인코딩을 쓰므로 보호된 페이로드의 첫 16바이트를 표본으로 잡아 헤더에 적용합니다.
sample = d1b1c98dd7689fb8ec11d242b123dc9b
mask = AES-ECB(hp, sample)[0..4]
= 437b9aec36
header = c000000001088394c8f03e5157080000449e7b9aec34
서버 Initial 패킷
서버는 ACK 프레임과 CRYPTO 프레임을 담고 PADDING 프레임은 담지 않은 페이로드로 답합니다.
02000000000600405a020000560303ee
fce7f7b37ba1d1632e96677825ddf739
88cfc79825df566dc5430b9a045a1200
130100002e00330024001d00209d3c94
0d89690b84d08a60993c144eca684d10
81287c834d5311bcf32bb9da1a002b00
020304
서버가 보내는 헤더에는 새 연결 ID 와, 패킷 번호 1을 담은 2바이트 패킷 번호 인코딩이 들어갑니다. 보호를 걸면 헤더 보호 표본은 보호된 세 번째 바이트부터 뜹니다.
sample = 2cd0991cd25b0aac406a5816b6394100
mask = 2ec0d8356a
header = cf000000010008f067a5502a4262b5004075c0d9
최종적으로 보호된 패킷은 이렇습니다.
cf000000010008f067a5502a4262b500
4075c0d95a482cd0991cd25b0aac406a
5816b6394100f37a1c69797554780bb3
8cc5a99f5ede4cf73c3ec2493a1839b3
dbcba3f6ea46c5b7684df3548e7ddeb9
c3bf9c73cc3f3bded74b562bfb19fb84
022f8ef4cdd93795d77d06edbb7aaf2f
58891850abbdca3d20398c276456cbc4
2158407dd074ee
Retry 패킷
같은 부록이 위 Initial 패킷에 대한 응답으로 보낼 법한 Retry 패킷도 싣습니다.
ff000000010008f067a5502a4262b574
6f6b656e04a265ba2eff4d829058fb3f
0f2496ba
무결성 검사에는 클라이언트가 고른 연결 ID 값 0x8394c8f03e515708 이 들어갑니다. 그 값 자체는 최종
Retry 패킷에 실리지 않습니다.
배경
HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) /1.1 은 공백으로 필드를 가르는 텍스트로 메시지를 나릅니다. 사람이 읽을 수 있다는 장점이 있지만, 공백으로 메시지 형식을 잡다 보니 파싱이 복잡해지고 제각각인 동작을 지나치게 허용하게 됩니다. 그리고 HTTP/1.1 에는 다중화 계층이 없어서, 요청을 병렬로 처리하려면 TCP 연결을 여러 개 쓰는 일이 잦습니다. TCP 는 여러 연결에 걸쳐 혼잡 제어를 공유하지 않으므로 이것이 혼잡 제어와 네트워크 효율에 부정적인 영향을 줍니다. HTTP/2 는 전송 계층을 건드리지 않고 지연을 개선하려고 이진 프레이밍과 다중화 계층을 들여왔습니다. 그런데 HTTP/2 다중화가 가진 병렬성이 TCP 의 손실 복구 메커니즘에는 보이지 않습니다. 그래서 패킷 하나가 유실되거나 순서가 뒤집히면, 그 패킷과 직접 상관이 없는 트랜잭션까지 포함해 진행 중인 모든 트랜잭션이 멈춥니다.
필요한 것은 스트림 수준에서 신뢰성을 주는 전송이었습니다. QUIC 은 HTTP/2 프레이밍 계층이 주던 것과 비슷한 스트림 다중화와 스트림별 흐름 제어를 전송 프로토콜 안으로 가져옵니다. 신뢰성은 스트림 수준에서 주고, 혼잡 제어는 연결 전체에 걸어서, TCP 매핑에 견주어 HTTP 성능을 개선할 여지를 가집니다. TLS 1.3 도 전송 계층에 함께 넣었습니다. TCP 위에서 TLS 를 돌릴 때와 견줄 만한 기밀성과 무결성을 주면서 연결 수립 지연은 TCP Fast Open 만큼 줄인 형태입니다. 이 전송을 UDP 데이터그램 위에 얹은 이유는 기존 시스템과 네트워크에 배치하기 쉽게 하려는 것입니다.
경로가 바뀌는 상황도 설계에 들어갔습니다. 연결 ID 를 쓰면 끝점 주소가 바뀌어도 연결이 살아남습니다. 끝점이 새 네트워크로 옮겨 가면서 IP 주소와 포트가 바뀌는 경우가 그렇습니다. 다만 QUIC 의 설계는 핸드셰이크가 도는 동안에는 끝점이 안정된 주소를 유지한다고 전제합니다. 끝점은 핸드셰이크가 확인되기 전에 연결 마이그레이션을 시작해서는 안 됩니다. 상대 주소가 바뀌는 일이 전부 의도된 마이그레이션인 것도 아닙니다. 중간 상자, 대개 NAT 가 흐름에 새 출발 포트나 새 출발 IP 주소를 할당하는 NAT 재바인딩이 그 예입니다. 끝점은 상대 주소가 바뀐 것을 감지하면 경로 검증을 수행해야 합니다. 앞서 그 주소를 검증해 둔 경우만 예외입니다.
관련 항목
스트림을 이루는 구성 요소
연결을 여는 핸드셰이크 절차
핸드셰이크 · 버전 협상 · 전송 파라미터
이른 데이터 전송이 여는 조건과 대가
RTT · 0-RTT · 재생 공격 · 세션 · 세션 티켓 · early data · 지연 · TCP Fast Open
연결을 새 경로로 옮기는 절차
연결 마이그레이션 · 연결 ID · 경로 검증 · NAT · NAT 재바인딩 · IP 주소
가짜 트래픽을 막는 장치
주소 검증 · 상태 없는 리셋 · 서비스 거부
TLS 핸드셰이크를 이루는 요소
TLS · TLS 1.3 · ClientHello · ALPN · 인증서 · 레코드 · 메시지 · 성능
패킷 보호와 인증을 이루는 성질
인증 · 헤더 보호 · 태그 · AEAD · 키 유도 함수
패킷의 하위 종류
Initial 패킷 · Handshake 패킷 · Retry 패킷 · 1-RTT 패킷 · 긴 헤더 · Short Header
프레임과 패킷을 다루는 방식
CRYPTO 프레임 · STREAM 프레임 · ACK 프레임 · PADDING 프레임 · HANDSHAKE_DONE · 패킷 번호 공간 · 병합
손실을 감지하고 복구하는 절차
손실 감지 · 혼잡 제어 · 손실 복구 · 재전송 · 확인 응답
QUIC 이 나오기 전 겪던 문제
HTTP/1.1 · HTTP/2 · TCP · 머리줄 막힘 · 트랜잭션
QUIC 이 놓이는 배치 환경
QUIC 를 정의하거나 그 위에 얹히는 명세
RFC 9000 · RFC 9001 · RFC 9002 · RFC 9114 · HTTP/3
다른 이름: QUIC version 1