[HTTP 이해하기 5편] 브라우저와 서버는 HTTP/1.1과 HTTP/2 중 무엇을 어떻게 결정할까
Today Key : HTTPS, TLS, TLS Handshake, ALPN, HTTP/1.1, HTTP/2, h2, h2c, ClientHello, ServerHello
이번 포스팅에서는 TLS 핸드셰이크와 ALPN을 중심으로 그 선택 과정의 원리를 정리해봅니다.
ALPN, 프로토콜 협상의 핵심
이 선택에서 핵심 역할을 하는 것이 ALPN(Application-Layer Protocol Negotiation)입니다.
RFC 7301은 ALPN을 같은 TCP나 UDP 포트에서 여러 애플리케이션 프로토콜을 지원할 때, TLS 핸드셰이크 안에서 어떤 프로토콜을 사용할지 정하기 위한 확장으로 정의합니다.
클라이언트는 자신이 지원하는 프로토콜 목록을 ClientHello에 넣어 보내고, 서버는 그중 하나를 선택해 응답합니다.
이 협상이 TLS 핸드셰이크 안에서 완료되기 때문에, 별도의 추가 왕복 없이 프로토콜을 정할 수 있습니다.
TLS 핸드셰이크 안에서의 협상 흐름
브라우저가 https://zigispace.net에 접속할 때 흐름은 아래처럼 정리할 수 있습니다.
| 1) 브라우저가 서버와 TCP 연결을 시작한다 2) 브라우저가 TLS ClientHello를 보낸다 3) ClientHello 안에 ALPN 후보 목록이 들어간다 4) 서버가 TLS 응답 안에서 사용할 프로토콜을 선택한다 5) 협상이 끝난 뒤 실제 HTTP 통신이 시작된다 |
겉으로는 웹페이지 하나를 여는 동작처럼 보이지만, "이 연결에서 어떤 HTTP 버전을 쓸지"를 먼저 정한 뒤에야 요청과 응답이 시작되는 구조입니다.
h2와 h2c의 구분
HTTP/2는 이 협상에서 조금 더 명확한 규칙을 가집니다.
RFC 9113은 https URI에 대해 HTTP/2를 시작할 때 TLS와 ALPN을 사용해야 한다고 설명하고, HTTP/2 over TLS의 프로토콜 식별자는 h2라고 정의합니다.
반대로 h2c는 TLS를 사용하지 않는 HTTP/2를 가리키므로, https 연결의 ALPN 협상에서는 클라이언트가 보내거나 서버가 선택해서는 안 된다고 명시하고 있습니다.
일반적인 브라우저 기반 HTTPS 접속에서 HTTP/2가 사용된다면, 그 실체는 대부분 h2입니다.
서버 설정이 최종 결과를 결정한다
브라우저가 HTTP/2를 지원한다고 해서 항상 HTTP/2가 선택되는 것은 아닙니다.
ALPN은 어디까지나 후보를 제시하고 하나를 선택하는 구조이기 때문에, 최종 결정은 서버 설정과 지원 범위에 따라 달라집니다.
Apache httpd 공식 문서는 HTTP/2를 사용하려면 mod_http2를 로드한 뒤 Protocols 지시어로 명시적으로 활성화해야 한다고 설명합니다.
보안 가상 호스트에서 아래처럼 설정하면 TLS ALPN을 통해 h2와 http/1.1을 협상할 수 있습니다.
| Protocols h2 http/1.1 |
서버가 HTTP/1.1만 허용하도록 구성되어 있다면, 브라우저가 HTTP/2를 쓸 수 있더라도 최종 결과는 HTTP/1.1이 됩니다.
"HTTP/2가 가능한 환경인가"와 "실제로 그 연결에서 HTTP/2가 선택되는가"는 같은 말이 아닙니다.
TLS 버전에 따라 달라지는 확인 위치
ALPN 협상 결과를 패킷에서 확인할 때는 TLS 버전에 따라 위치가 달라집니다.
| TLS 1.2 | TLS 1.3 | |
| 브라우저 제안 | ClientHello | ClientHello |
| 서버 선택 결과 | ServerHello |
RFC 8446은 application_layer_protocol_negotiation 확장이 TLS 1.3에서 ClientHello와 EncryptedExtensions에 위치한다고 설명하고, EncryptedExtensions가 ServerHello 바로 다음에 오는 첫 번째 암호화 메시지라고 정의합니다.
브라우저와 서버가 프로토콜을 정하는 원리는 같지만, 패킷에서 그 선택 결과가 보이는 위치는 TLS 버전에 따라 달라집니다.
이후 Wireshark로 실제 랩을 확인할 때 이 기준을 알고 있으면 훨씬 덜 헷갈립니다.
http:// 접속과 https:// 접속의 차이
ALPN은 TLS 확장이기 때문에, TLS가 없는 일반 HTTP 연결에는 ALPN이 없습니다.
Apache는 서버 컨텍스트에서 Protocols h2 h2c http/1.1처럼 설정해 cleartext HTTP/2도 다룰 수 있고, h2c는 초기 HTTP/1.1 연결에서 업그레이드하거나 direct mode로 사용할 수 있습니다.
다만 브라우저에서 접속하는 일반적인 HTTPS 웹 서비스 관점에서는 h2와 ALPN 중심으로 이해하는 것이 우선입니다.
정리하면, 브라우저와 서버가 HTTP/1.1과 HTTP/2 중 무엇을 사용할지는 웹 요청을 보내고 나서가 아니라 TLS 연결을 만드는 순간에 대부분 결정됩니다.
클라이언트는 ClientHello 안에 지원 가능한 프로토콜 후보를 넣어 보내고, 서버는 그중 하나를 선택하며, 그 결과가 이후 연결 전체의 HTTP 버전을 결정합니다.
HTTPS에서 HTTP/2를 사용할 때 식별자는 h2이며, Apache 같은 웹서버에서 Protocols h2 http/1.1 같은 설정으로 미리 준비해 두어야 합니다.
다음 포스팅에서는 리눅스 환경에 Apache httpd를 올리고 HTTP/1.1과 HTTP/2를 각각 활성화하는 과정을, 실습 중심으로 이어서 살펴보겠습니다.