요약
- TLS 1.3의 0-RTT는 재접속 클라이언트가 ClientHello와 함께 애플리케이션 데이터를 보낼 수 있게 하여 왕복 1~2회를 줄입니다. early data는 암호화되어 있지만, 일반적인 1-RTT 데이터와 달리 연결 간 재전송 방지(replay 방지) 보장이 없습니다.
- RFC 8470은 TLS가 스스로 만들 수 없는 HTTP의 리소스 수준 해법을 제시했습니다.
Early-Data: 1로 중개자를 거치는 early-data 이력을 전달하고, 원본 서버가 처리 위험을 감수하지 않으려 할 때425 Too Early로 응답할 수 있게 한 것입니다. - 425 재시도는 요청의 의도된 작업을 유지하되 암호학적 시점을 바꿉니다. 클라이언트는 자동으로 재시도해야 하며, 그 재시도는 early data를 사용해서는 안 됩니다. HTTP/3도 QUIC 위에서 동일한 replay 규칙을 유지합니다.
서버가 말하기 전에 시작된 지름길
전통적인 보안 요청은 기다립니다. 클라이언트와 서버가 핸드셰이크 메시지를 주고받아 새 트래픽 비밀값을 도출하고, 애플리케이션 데이터가 오갈 조건을 확립합니다. 그 후에야 브라우저나 API 클라이언트가 HTTP 작업을 보냅니다. 먼 경로에서는 빛의 속도조차 이 순서를 지연으로 드러냅니다.
TLS 1.3은 최근에 같은 서버와 통신한 클라이언트를 위한 더 빠른 경로를 만들었습니다. 서버는 재개(resumption) 재료를 발급할 수 있고, 이후 연결에서 클라이언트는 그 기억된 상태를 제시하며 ClientHello 옆에 애플리케이션 데이터를 놓을 수 있습니다. 요청은 더 이상 새 ServerHello를 기다리지 않습니다. HTTP에서 이 "early data", 즉 0-RTT는 요청 앞에 오는 왕복 1~2회를 제거할 수 있습니다.
이 최적화가 핸드셰이크를 무의미하게 만든 것은 아닙니다. 유용한 작업을 새로운 확인보다 앞으로 옮긴 것입니다. 이 구분이 425의 역사 전부입니다.
TLS 1.3 명세는 이 더 약한 거래를 명확히 말합니다. Early data는 제공된 사전 공유 키에서 파생된 키로 암호화되기 때문에 forward secret이 아닙니다. 더 좁게는, 연결 간 replay 방지 보장이 없습니다. 일반 TLS 1.3 애플리케이션 데이터는 새 ServerHello와 그 서버 랜덤값에 의존하지만, 0-RTT 데이터는 이미 클라이언트를 떠났기 때문에 그럴 수 없습니다.
이것이 0-RTT가 평문이거나, 인증이 없거나, 자유롭게 변조 가능하다는 뜻은 아닙니다. 공격자가 같은 early 바이트를 한 연결 안에서 두 번 나타나게 하거나, 그것을 일반 1-RTT 데이터로 바꿀 수는 없습니다. 노출된 경계는 더 정밀합니다. 캡처된 early 플라이트(flflight)가 다른 연결에서 제시될 수 있다는 것입니다.
Replay와 retry는 같지 않으면서 만날 수 있다
네트워크 소프트웨어는 언제나 재시도했습니다. 클라이언트가 응답을 잃거나, 연결이 끊기거나, 사용자가 버튼을 다시 누릅니다. 이들은 불완전하지만 엔드포인트의 가시적인 판단입니다.RFC 8470에서 쓰는 의미의 replay는 클라이언트 모르게 공격자가 복제하는 것입니다.
둘은 겹칠 수 있습니다. 동일한 replay 상태를 갖지 않는 두 존(zone)을 가진 분산 서비스를 상상해 보십시오. 공격자가 ClientHello와 early 요청을 복사해 양쪽에 보냅니다. 존 A는 0-RTT 데이터를 받아 처리합니다. 존 B는 early data를 거부하고 전체 핸드셰이크를 완료합니다. 공격자가 A의 응답을 숨기면, 클라이언트는 B와 계속하며 처리된 적이 없다고 믿는 요청을 정당하게 다시 보낼 수 있습니다. 하나의 작업이 두 가지 다른 메커니즘으로 두 번 도착한 것입니다.
TLS 1.3은 두 클래스를 모두 다룹니다. 서버는 최근 ClientHello를 기록하거나, 세션 티켓을 한 번만 소비하거나, 신선도(freshness) 창을 사용하거나, 하나의 권위 있는 티켓 존을 지정할 수 있습니다. 이런 조치는 직접 복제를 제한할 수 있지만, 기계·지역·재시작 전반의 어려운 일관성을 요구합니다. 표준은 서버 인스턴스당 최대 한 번 수용을 최소 기준으로 삼고, 가능한 곳에서는 더 엄격한 한계를 권장합니다.
그러나 retry가 겹치는 클래스는 TLS 안에서 해결될 수 없습니다. 암호 계층은 레코드와 핸드셰이크만 보며, 어떤 메시지가 토큰을 소진하거나 좌석을 예약하거나 감사 이벤트를 기록하거나 단지 불활성 스타일시트를 가져오는지 알지 못합니다. "두 번 안전"이 무엇인지 판단할 수 없습니다.
그래서 TLS 1.3은 애플리케이션 프로토콜이 0-RTT를 함부로 켜지 못하게 금지합니다. 프로토콜은 어떤 상호작용이 이를 사용할 수 있고, 서버가 거부할 때 무엇이 일어나는지를 정하는 프로파일이 필요합니다. TLS 라이브러리가 독단으로 early data를 켜거나 거부된 바이트를 자동 재전송해서는 안 됩니다. 이것은 애플리케이션의 결정입니다.
메서드 이름은 증거였지 판결이 아니었다
HTTP에는 그 결정을 위한 편리한 어휘가 있는 듯 보였습니다.GET과HEAD는 안전(safe) 메서드로 정의되어 있고,PUT과DELETE는 멱등(idempotent)이며,POST는 변화를 수반하는 경우가 많습니다. 더 나은 정보가 없는 클라이언트는 안전 메서드를 early data로 보낼 수 있고, 안전하지 않거나 안전 여부를 알 수 없다고 알려진 메서드를 보내서는 안 됩니다.
그러나 RFC 8470은 메서드 의미론을 리소스의 완전한 모델과 혼동하는 것을 거부했습니다. 명목상 안전한 요청도 미터기를 증가시키거나, 일회성 서명 URL을 소진하거나, 비싼 백엔드를 예열하거나, 캐시를 바꾸거나, 중복이 문제가 되는 로깅을 유발할 수 있습니다. 멱등인 작업을 여러 번 replay하면 한도를 소진시키거나 타이밍 정보를 노출할 수 있습니다. 반대로 명시적 트랜잭션 설계를 갖춘 애플리케이션은 메서드 토큰이 드러내는 것보다 더 많이 압니다.
그 리소스별 지식은 보통 원본 서버만 갖습니다. 클라이언트는 early로 보낼지 결정하고, TLS 엔드포인트는 early 플라이트를 수용할지 결정하고, 게이트웨이는 라우팅을 보고, 애플리케이션은 결과를 압니다. HTTP는 앞의 세 주체의 낙관을, 기능을 전면 끄지 않고 마지막 주체가 거부할 수 있는 방법이 필요했습니다.
선행 효과를 거부하는 세 가지 방법
RFC 8470은 동등하게 유효한 세 가지 보호를 기술합니다.
첫째, 서버는 TLS 수준에서 early 플라이트 전체를 거부할 수 있습니다. 간단하고 광범위합니다. TLS는 하나의 early HTTP 요청만 선택적으로 남기고 다른 것을 버릴 수 없으므로, 그 플라이트의 모든 요청이 지연 이점을 잃습니다.
둘째, HTTP 서버는 핸드셰이크가 완료될 때까지 처리를 지연할 수 있습니다. 헤더를 파싱하거나 경로를 고르되 효과를 피하고, 새로운 연결 상태가 존재하는 시점에 각 요청을 놓아줄 수 있습니다. 멀티플렉싱 프로토콜에서는 함께 도착했더라도 요청마다 다른 정책을 적용할 수 있습니다.
셋째, 서버는 한 요청에425 Too Early로 응답할 수 있습니다. 이 상태는 replay될 가능성이 있는 요청을 처리할 위험을 감수하기 싫다는 뜻입니다. 결정을 클라이언트에 돌리고, 클라이언트는 early data 없이 요청을 다시 보낼 수 있습니다.
셋째 선택이 중요한 이유는 0-RTT를 전역 스위치에서 리소스 수준의 특권으로 바꾸기 때문입니다. 공개 에셋은 빠른 경로를 쓰고 토큰 상환은 기다릴 수 있습니다. 원본 서버는 두 작업이 하나의 위험 프로필을 공유한다고 가장할 필요가 없습니다.
한 비트가 게이트웨이를 통과해야 했다
리소스를 이해하는 원본 서버가 클라이언트의 TLS 연결을 종료하지 않을 수 있습니다. 브라우저가 CDN과 통신하고, CDN이 게이트웨이로 전달하고, 게이트웨이가 애플리케이션을 호출할 수 있습니다. 요청이 그 결과를 아는 코드에 도달할 때쯤에는 원래 핸드셰이크가 여러 홉 거리에 있습니다.
그래서 RFC 8470은 유효값이 하나뿐인Early-Data요청 헤더 필드, 즉1을 정의했습니다. 클라이언트 측 핸드셰이크가 완료되기 전에 전달하는 중개자는 이 값을 추가해야 합니다. 이 값을 본 중개자는 제거해서는 안 됩니다. 요청이 다른 인스턴스에 의해 이미 전달되었을 가능성이 있다면 비트는 그대로 설정된 상태를 유지합니다.
이 작은 필드는 선호가 아니라 이력을 담습니다. "빨리 가 달라"는 말이 아닙니다. replay가 가능했던 동안 어떤 업스트림 사본이 존재했을 수 있고, 사용자 에이전트가 425 복구 규약을 이해한다는 뜻입니다.
이 이력은 이후 핸드셰이크를 기다린다고 지워지지 않습니다. CDN이 early data로 요청을 받아 표시하고, 원본 서버로는 완전히 수립된 일반 연결을 열었다고 가정하십시오. 원본 서버는 자기 홉이 이제 1-RTT라는 이유만으로 요청을 안전하다고 선언할 수 없습니다. 가능한 중복은 이전 홉에 속합니다. 표시된 요청을 안전하게 처리할 수 없다면 원본 서버는 425를 반환해야 합니다.
여러 개 또는 형식이 잘못된 인스턴스는 동일한 단일 위험 비트로 취급됩니다. 이 필드는 응답이나 요청 트레일러에는 나타나지 않습니다. 화려한 신뢰 주장이 되지 않도록 의도적으로 너무 작게 설계된 것이며, 다운스트림 주체가 필요로 하는 단 하나의 사실을 보존합니다.
425가 바꾸는 것, 그리고 유지하는 것
사용자 에이전트가 early data로 요청을 보냈고 425를 받았다면 자동으로 재시도해야 합니다. 결정적 규칙은 재시도 자체가 early data여서는 안 된다는 것입니다. 클라이언트는 핸드셰이크를 기다린 뒤 일반 애플리케이션 데이터를 전송합니다.
URI를 바꿀 필요는 없습니다. 메서드도, 페이로드와 의도된 작업도 바꿀 필요가 없습니다. 리다이렉트와 달리 425는 다른 리소스를 지명하지 않습니다. 421과 달리 선택된 연결이 해당 원본에 대한 권한이 없다고 말하지 않습니다. 같은 서버가 한순간 뒤에는 완전히 건강한 상태로 그 요청을 처리할 준비가 되어 있을 수 있습니다.
이 상태는 429의 요율 제한도, 503의 서비스 불가도 아닙니다. 쿼터도 일반적인 "나중에" 간격도 제시하지 않습니다. 빠져 있는 조건은 여유 용량이 아니라 완성된 암호학적 컨텍스트입니다. 100 Continue도 아닙니다. 정보성 응답인 100 Continue는 클라이언트가 본문을 보낼지 판단하도록 돕지만, 425는 replay 가능성이 있는 요청을 처리하지 않겠다는 최종 거부입니다.
서버는 early data로 도착하지도 않았고 헤더를 갖고 있지도 않은 일반 요청에 425를 내보내서는 안 됩니다. 그 증거가 없다면 서버는 클라이언트가 특수한 재시도 규칙을 알고 있다고 가정할 수 없습니다. 이 응답은 기본적으로 캐시할 수 없으며, 본문은 요청된 리소스의 표현(representation)이 아닙니다.IANA 레지스트리는 좁은 이름 "Too Early"를 기록하고 RFC 8470을 가리킵니다.
중개자가 모두 같은 이력을 복구할 수는 없다
중개자는 언제나 425를 전달할 수 있습니다. 요청이Early-Data: 1과 함께 도착했다면 반드시 전달해야 합니다. replay 노출은 중개자가 지울 수 없는 업스트림에서 시작되었기 때문입니다.
의도적으로 비대칭인 경우가 하나 있습니다. 중개자 자신이 요청을 early data로 받았고, 이전 홉에서 이미 표시되어 온 것이 아니라면, 425를 흡수하고 원본 서버를 향해 재시도할 수 있습니다. 그 전에 클라이언트 대면 핸드셰이크가 완료되기를 기다려야 합니다. early 이력이 어디서 시작되었는지 아는 바로 그 엣지가 요청을 안전한 시점으로 옮길 수 있습니다.
게이트웨이는 원본 서버가 헤더를 이해하고 425를 정확히 생성할 수 있음을 알지 못하는 한 early 요청을 전달해서는 안 됩니다. 그렇지 않다면 기다리거나 거부해야 합니다. 엣지에서 0-RTT를 켜면서 인지하지 못하는 애플리케이션에게 이를 숨기면, 인프라가 애플리케이션이 볼 수 없는 위험에 그를 대신 동의시키게 됩니다.
도착 시각보다 실행 시각이 중요하다
HTTP 요청은 핸드셰이크 경계에 걸칠 수 있습니다. 헤더는 이르게 도착하고 본문은 나중에 올 수 있습니다. QUIC에서는 스트림 스케줄링 때문에 early로 표시된 데이터가 핸드셰이크 완료 후에 도달할 수도 있습니다. 따라서 마지막 바이트의 벽시계 관찰은 불충분합니다.
RFC 8470은 서버가 언제 행동을 시작하는지를 묻습니다. 경로를 식별할 만큼의 파싱은 무해할 수 있지만, 트랜잭션 커밋이나 백엔드 호출 시작이나 캐시 변경은 그럴 수 없습니다. 어떤 인스턴스라도 완료 전에 효과를 일으킬 수 있다면, replay를 받을 수 있는 모든 인스턴스가 동일한 안전 불변식을 강제해야 합니다.
이것은 상태 코드로 위장한 분산 시스템 규칙입니다. 인스턴스들은 서로 다른 완화책을 쓸 수 있습니다. 하나는 early data를 거부하고, 다른 하나는 기다리고, 셋째는 425를 내보내지만, 어느 것도 다른 인스턴스가 다르게 다룰 요청에 대해 이르게 행동해서는 안 됩니다. 새로 재시작한 노드는 시작 전에 누적된 replay 이력이 없으므로, 기록 창이 그 맹시기와 겹치는 동안 0-RTT를 거부해야 합니다.
HTTP/3는 경계를 살려 두었다
HTTP를 TCP에서 QUIC로 옮긴 것이 문제를 없애지는 못했습니다.RFC 9114는 RFC 8470의 replay 완화책을 HTTP/3 0-RTT에 명시적으로 적용합니다. 핸드셰이크는 QUIC 안의 TLS이고, 애플리케이션 데이터는 스트림으로 운반되지만, 의무는 그대로입니다.
HTTP/3는 별개의 호환성 문제를 더합니다. early 요청을 보내는 클라이언트는 새 연결의 SETTINGS를 아직 받지 못했으므로 이전 세션에서 기억한 값에 의존합니다. 서버는 그 기억된 값이 현재 설정과 호환됨을 증명할 수 없다면 0-RTT를 거부해야 합니다. 데이터를 받아들이면, 나중에 보내는 SETTINGS가 early 요청이 이미 위반했을 수 있는 방식으로 한도를 줄여서는 안 됩니다.
SETTINGS 호환성은 425 결정이 아닙니다. 하나는 프로토콜의 공유 상태를 보호하고, 다른 하나는 리소스의 효과를 보호합니다. 둘의 공존은 요청이 기다림으로써 공짜로 얻던 증명이 얼마나 많은 종류였는지 보여줍니다.
HTTP 425는 그 증명 중 하나를 명시적으로 만들었습니다. "너무 이르다"는 콘텐츠의 나이나 사용자의 조급함을 말하지 않습니다. 요청이 그 경로가 결과를 안전하게 승인할 수 있기 전에 도착한 순간을 말합니다.
출처와 증거의 한계
프로토콜 기록은TLS 1.3, RFC 8446,Using Early Data in HTTP, RFC 8470,HTTP/3, RFC 9114, 그리고 현재의IANA HTTP 상태 코드 레지스트리입니다. 이 출처들은 명세된 지연 트레이드, replay 경계, 중개자 의무, 복구 규칙, HTTP/3 연속성을 확립합니다. 이 출처들은 현재 배포 점유율, 보편적 클라이언트 지원, 실명이 밝혀진 공격 사례, 특정 서비스의 측정된 절감 효과, 또는 exactly-once 애플리케이션 동작을 확립하지 않습니다.
회원 브리핑
프로필 심층 컨텍스트
올바른 멤버십 등급으로 로그인하면 전체 브리핑과 출처 노트를 볼 수 있습니다.
Strategic Circle 전용
Strategic Circle
모든 독자에게 공개됩니다. 가입 후 로그인하면 프로필 브리핑를 열람할 수 있습니다.
Strategic Circle 가입하기Leadership Alliance 전용
Leadership Alliance
자격을 갖춘 IP 자산 소유자 및 운영진을 위한 콘텐츠입니다. 로그인하면 Leadership Alliance 브리핑을 열람할 수 있습니다.
Leadership Alliance 가입하기





