요약

  • RFC 9931은 HTTP/1.1의 위험한 증거 공백을 닫습니다. Upgrade 또는 CONNECT 요청의 완료는 서버가 전환을 수락했음을 확인하지 않습니다. 최근의 성공은 예측을 정당화할 수 있지만, 현재 연결의 파서 또는 터널 상태를 확립하는 것은 오직 현재 응답뿐입니다.
  • 신뢰된 클라이언트가 응답에 앞서 신뢰할 수 없는 제3자 바이트를 내보내면, 거부가 발생했을 때 서버가 새 프로토콜 데이터를 또 다른 HTTP/1.1 요청으로 읽을 수 있습니다. 운영자는 페이로드 자체를 기록하지 않으면서 확인 경계 — 무엇이 보류되었는지, 어떤 응답이 도착했는지, 어떤 규칙이 바이트를 내보냈고 어떤 파서가 권위를 가졌는지 — 를 보존해야 합니다.

빠른 경로는 확실성을 받기도 전에 쓴다

지연 최적화는 흔히 시간을 빌리는 것처럼 설명됩니다. 낙관적인 클라이언트는 그 프로토콜을 만들 요청이 아직 답을 기다리는 동안, 다음 프로토콜이 소비할 것으로 기대하는 데이터를 보냅니다. 예측이 맞으면 한 번의 대기가 사라집니다. 틀리면 손실은 단순히 더 느린 재시도가 아닙니다. 동일한 옥텟이 수신자가 서로 다른 문법과 서로 다른 권한 주체를 부여하는 상태로 도착할 수 있습니다.

2026년 3월 IETF Standards Track으로 발표된 RFC 9931은 HTTP/1.1 연결에서 이루어지는 전환에 대해 이 문제를 분리해 다룹니다. 이 문서는 HTTP/1.1과 UDP-over-HTTP 명세를 갱신합니다. 핵심 구분은 트레이스에서 거의 동일하게 보이는 두 인접 사건 — 클라이언트가 연결 변경을 요청하는 것을 마쳤다는 사실과, 서버가 변경에 동의했다는 사실 — 때문에 놓치기 쉽습니다.

두 사건은 같지 않습니다. HTTP Upgrade는 클라이언트가 다른 응용 프로토콜을 제안하게 합니다.101 Switching Protocols응답은 서버가 이를 이해하고 따를 의사가 있으며, 응답 이후 적용될 프로토콜을 명시한다는 뜻입니다. CONNECT는 프록시에 터널 형성을 요청합니다. 성공적인 2xx 응답은 응답 헤더 구간 이후 터널 모드가 시작됨을 의미하며, 그 외의 응답은 터널이 형성되지 않았음을 의미합니다.

HTTP 의미론은 이미 클라이언트가 요청 도중에 업그레이드된 프로토콜을 시작할 수 없다고 말합니다. RFC 9931은 나머지 절반을 명시합니다. 요청을 완료하는 것은 필요조건이지만 충분조건이 아닙니다. 서버는 토큰이 없거나, 인증을 요구하거나, 목적지를 거부하거나, 해결하지 못하거나, 자원을 사양하거나, 단순히 전환이 유용하지 않다고 판단할 수 있습니다. 답이 도착하기 전까지 클라이언트가 갖는 것은 기대이지 연결 상태의 사실이 아닙니다.

기억은 응답이 아니다

이 구분을 지우려는 유혹은 예측이 대개 맞을 때 가장 강합니다. 같은 토큰이 방금 전에 통했습니다. 같은 프록시는 해당 범주의 거의 모든 목적지를 수락합니다. 캐시된 기능 탐색은 녹색입니다. 공급업체는 배포가 전환을 지원한다고 말합니다. 대시보드는 무시할 수 있는 거부율을 보여줍니다.

이러한 관찰은 모두 유용할 수 있습니다. 용량 계획에 정보를 주고, 출시 코호트를 선택하고, 지연 절감이 추구할 가치가 있는지 추정하는 데 도움을 줍니다. 그러나 어느 것도 이 요청에 대한 응답이 아닙니다. 연결 사이에서 조건은 바뀔 수 있습니다. 자격 증명이 만료되고, 라우팅이 실패하고, 목적지 정책이 바뀌고, 중개자가 삽입되고, 서비스가 재시작되고, 자원이 이동하고, 요청이 다른 백엔드에 도달할 수 있습니다. 더 근본적으로, 수락은 서버의 현재 평가에 속합니다. 빈도는 아직 일어나지 않은 긍정적 응답을 만들어낼 수 없습니다.

이것이 거버넌스 경계인 이유는 여러 관리 주체가 같은 바이트에서 만나기 때문입니다. 제3자 애플리케이션이 페이로드를 선택합니다. HTTP 클라이언트가 언제 내보낼지 결정합니다. 프록시나 서버가 해석을 변경할지 결정합니다. 플랫폼 팀이 최적화 정책을, 보안 팀이 요청 밀수 통제를, 공급업체가 호환성 성명을 소유할 수 있습니다. 트레이스가 “업그레이드 시도됨”과 “바이트 전송됨”만 기록하면, 이후 검토자는 누구의 결정이 데이터를 통과시켰는지, 어떤 문법이 적용되었는지 알 수 없습니다.

유용한 바로잡음은 예측을 무가치하다고 부르는 것이 아니라 정직하게 이름을 붙이는 것입니다. 과거의 성공은 가능성에 대한 증거입니다. 응답은 현재 프로토콜 상태에 대한 증거입니다. 둘은 높은 상관을 보일 수 있으면서도 서로 대체 불가능합니다.

같은 바이트에 두 명의 작성자가 생길 때

각 단말이 이미 서로에게서 임의의 입력을 기대하는 양자 연결에서는, 잘못된 예측이 이 특정 보안 문제 없이도 프로토콜 오류가 될 수 있습니다. RFC 9931은 더 어려운 배치에 주목합니다. HTTP 클라이언트는 서버가 신뢰하지만, 클라이언트 뒤의 데이터 출처는 그렇지 않은 경우입니다.

로컬 애플리케이션이 인증된 프록시 클라이언트에게 TCP 터널을 요청한다고 가정합니다. 애플리케이션은 즉시 원격 TCP 서비스를 위한 바이트를 공급합니다. 클라이언트는 프록시가 성공적인 CONNECT 응답을 돌려주기 전에 그것을 전달합니다. 목적지가 실패하면 프록시는 CONNECT를 거부하고 HTTP/1.1 모드에 머무릅니다. 애플리케이션이 다른 프로토콜을 위해 작성한 바이트가 이제 프록시가 다음 HTTP 요청을 기대하는 자리에 놓입니다.

공격자는 그 바이트를 프록시 자신에 대한 유효한 요청처럼 보이도록 조각낼 수 있습니다. 연결이 클라이언트 인증서나 다른 연결 수준 신원을 담고 있을 수 있으므로, 프록시는 주입된 요청을 신뢰된 클라이언트에 귀속시킬 수 있습니다. 애플리케이션은 사실상 주어진 적 없는 권한으로 말한 셈입니다. RFC 9112는 더 넓은 요청 밀수 범주를 수신자들 간 구문 분석 차이를 이용해 정책상 차단될 수 있는 요청을 은폐하는 것으로 설명합니다.

따라서 이 실패에는 세 층이 있습니다. 예측 오류: 전환이 일어나지 않았다. 프레이밍 오류: 송신자와 수신자가 어느 프로토콜이 바이트를 구문 분석하는지 불일치한다. 권한 오류: 한 주체가 고른 데이터가 다른 주체의 요청으로 처리된다. 실패한 업그레이드만 세면 첫 층만 보이고 그 결과는 놓칩니다.

구문 분석 악용은 바이트 열이 완전한 밀수 요청이 아닐 때도 발생할 수 있습니다. 요청 자료가 신뢰된 HTTP 클라이언트에서 왔다는 가정 위에 작성된 소프트웨어는 공격자가 통제하는 입력을 만날 수 있습니다. 요점은 거부된 모든 전환이 악용으로 이어진다는 것이 아닙니다. 조기 내보내기는 수신자가 누구의 문법과 누구의 권한이 적용되는지 알 수 있게 해주던 경계를 제거한다는 것입니다.

프로토콜 계열에는 낙관에 대한 규칙이 하나가 아니다

RFC 9931은 왕복을 줄이려는 모든 시도를 금지하지 않습니다. 메커니즘을 그것이 만드는 모호성으로 구분합니다.

WebSocket은 이미 보수적 경로를 택합니다. 개시 핸드셰이크를 보낸 후 클라이언트는 서버의 응답을 기다려야 더 많은 데이터를 보낼 수 있습니다. 고정된 대기 규칙은 거부 후 WebSocket 프레임이 HTTP/1.1 파서에 제시되는 일을 막습니다. WebSocket은 또한 클라이언트-서버 프레임을 마스킹하는데, 이는 프레임이 HTTP 요청으로 재활용되기 어렵게 만드는 별개의 설계 속성입니다.

이전 UDP-over-HTTP 문서는 클라이언트가 프록싱 응답을 받기 전에 프록시된 UDP 패킷을 보내는 것을 허용했습니다. RFC 9931은 그 허용을 좁힙니다. 낙관은 HTTP/2 이상에서는 허용되지만 HTTP/1.x에서는 허용되지 않습니다. IP-over-HTTP 명세도 같은 경계를 따릅니다. HTTP/2 또는 HTTP/3에서의 조기 패킷은 허용하고 HTTP/1.x에서는 금지하며, 더 새로운 HTTP 버전을 HTTP/1.1로 변환하는 중개자는 성공적인 프록싱 응답을 구문 분석할 때까지 캡슐을 보류해야 합니다.

이 구분은 구조적입니다. 연결상의 HTTP/1.1 요청은 순차적이며 그 분리는 암묵적입니다. HTTP/2와 HTTP/3는 명시적 스트림으로 요청을 식별합니다. 이는 거부된 전환을 위해 준비된 바이트가 다음 HTTP/1.1 요청으로 흘러드는 이 특정 사례를 피합니다. 그러나 모든 상위 버전 배포가 안전하다는 것, 모든 터널 목적지가 승인되었다는 것, 터널 페이로드가 안전하다는 것을 증명하지 않습니다. 하나의 모호성을 닫을 뿐 모든 위험을 닫는 것은 아닙니다.

미래의 Upgrade 토큰에 대해 RFC 9931은 몇 가지 설계 옵션을 제시합니다. 낙관적 사용을 금지하거나, HTTP/1.1 처리를 의도적으로 종결하는 고정 프리앰블로 새 프로토콜을 시작하거나, 높은 엔트로피의 마스킹을 사용하는 것입니다. 업그레이드된 프로토콜이 요청 메서드의 의미를 보존하지 않는다면, 내용 없는 GET을 사용하는 것도 경쟁하는 해석에 노출되는 자료를 줄입니다.

IANA의 레지스트리는 다른 사실을 기여합니다. 토큰 이름과 그 참조를 기록합니다. 등록은 참여자가 이름을 일관되게 해석하도록 돕습니다. 특정 단말이 지금 그 토큰을 지원한다는 것, 특정 요청이 수락될 것이라는 것을 알리지 않습니다. 레지스트리의 존재는 명세 출처인 것이지 실시간 전환 확인이 아닙니다.

이제 CONNECT에는 양방향 봉쇄 규칙이 있다

신뢰할 수 없는 TCP 클라이언트를 대리하는 HTTP/1.1 프록시 클라이언트에 대해 RFC 9931은 두 행동 중 적어도 하나를 요구합니다. TCP 페이로드를 전달하기 전에 성공적인 2xx 응답을 기다리거나,Connection: close를 포함해 거부가 같은 연결을 조기 자료를 또 다른 요청으로 구문 분석할 수 있는 상태로 남겨두지 않도록 하는 것입니다. 클라이언트는 둘 다 할 수 있습니다.

이 갱신은 거부하는 프록시 서버에도 봉쇄 의무를 부여합니다. 추가 요청을 처리하지 않고 기저 연결을 닫는 것입니다. 이는 너무 일찍 데이터를 내보내는 클라이언트로부터 보호합니다. 특히 407 인증 도전 이후 같은 연결에서 또 다른 요청이 이어질 수 있는 경우에는 성능 비용이 들 수 있습니다.

그 비용은 예외 압력을 만듭니다. RFC는 클라이언트가 2xx를 기다리는 것으로 알려진 경우 서버가 거부 시 닫기 완화를 비활성화할 수 있도록 하고, User-Agent와 공급업체 문서가 준수 클라이언트를 식별할 수 있다고 적시합니다. 이는 실용적인 운영 허용이지 인증된 증명 프로토콜이 아닙니다. RFC 9110은 User-Agent를 기원 소프트웨어에 대한 정보로 정의하고 사칭을 만류합니다. 따라서 내구성 있는 예외 결정은 단순한 제품 토큰 이상을 보존해야 합니다. 제품과 버전 범위, 검토된 공급업체 주장, 로컬 검증, 소유자, 만료 조건, 롤백 규칙이 그 대상입니다.

요점은 예외를 불가능하게 만드는 것이 아닙니다. 성능 선택이 영구적 속설이 되는 것을 막는 것입니다. “이 클라이언트는 안전하다”는 주장은 버전, 중개자, 구성이 바뀔 때 근거가 만료될 수 있는 날짜가 표시된 명제로 남아야 합니다.

전환 확인 영수증

전송 프로토콜은 이미 전환을 해소하는 응답을 담고 있습니다. 흔히 빠진 것은 그 응답을 제3자 바이트의 내보내기와 연결하는 운영자 기록입니다. 저는 이 구분이 보안적 결과를 갖는 경로를 위해 간결한 전환 확인 영수증을 제안합니다.

영수증은 연결 에포크와 HTTP 버전으로 시작합니다. 메커니즘이 Upgrade였는지 CONNECT였는지, 요청된 토큰 또는 터널 유형, 필요한 경우 보호 또는 해시 형태의 목적지를 식별합니다. 전환 후 데이터의 출처 — 제1주체 통제, 경계가 정해진 하위 시스템 또는 신뢰할 수 없는 제3자 — 를 데이터를 복제하지 않고 분류합니다.

다음으로 게이트를 기록합니다. 어떤 구현과 정책 버전이 바이트가 이동할 수 있는 시점을 결정했습니까?101또는 2xx를 기다렸습니까,Connection: close를 보냈습니까, 고정 프리앰블에 의존했습니까, 마스킹을 사용했습니까, 명시적으로 분리된 HTTP/2 또는 HTTP/3 스트림에서 작동했습니까? 현재 응답 전에 어떤 바이트라도 전달되었습니까? 그렇다면 그것은 낙관적 희망이 아니라 어떤 허용된 설계 아래였습니까?

그런 다음 결과를 결합합니다. 응답 클래스, 해당되는 경우 선택된 프로토콜, 최종 파서 또는 터널 상태, 거부 후 연결 처분, 봉쇄 조치. 예외 블록은 근거, 범위, 승인자, 만료, 무효화 트리거를 명시합니다. 소프트웨어 업데이트, 정책 변경, 새 중개자, 신원 변경, 실패한 카나리는 오래된 결정을 은밀히 상속하는 대신 새로운 결정을 열어야 합니다.

기록에는 터널 페이로드, 자격 증명, 클라이언트 인증서, 원시 응용 데이터 또는 비밀이 담기지 않아야 합니다. 작은 다이제스트와 구조화된 상태만으로도 거버넌스 질문에 답하기에 충분합니다. 어떤 현재 사건이 이 바이트들이 한 해석기에서 다른 해석기로 건너는 것을 허용했습니까?

이 영수증은 RFC 9931의 일부가 아닙니다. 프로토콜에 기업 승인 시스템이 되도록 요구하지 않으면서 RFC의 경계를 소비하는 운영 통제입니다. 서버 응답이 과대 해석되는 것도 막습니다. 2xx CONNECT 응답은 터널 형성을 확인할 뿐, 터널 안의 모든 애플리케이션 행동을 승인하지는 않습니다. 다음 계층은 여전히 자신의 신원과 정책 결정을 소유합니다.

이 분석이 확립하지 않는 것

동결된 출처는 프로토콜 의미론과 조건부 위험을 설명합니다. 특정 제품이 취약하다는 것, 운영자들이 흔히 페이로드를 조기 전달한다는 것, 특정 악용이 발생했다는 것, 하나의 완화가 모든 아키텍처에 맞는다는 것을 보여주지 않습니다. 양자 전환은 제3자 권한 문제를 전혀 드러내지 않을 수 있습니다. 더 새로운 HTTP 버전은 이 프레이밍 모호성을 피하지만 무관한 실패를 가질 수 있습니다.

또한 이 기사가 표준 갱신을 지연이 더 이상 중요하지 않다는 주장으로 바꾸어서는 안 됩니다. 강제 닫기는 인증과 재연결을 느리게 할 수 있습니다. 버퍼링은 지연이나 메모리 압박을 더할 수 있습니다. 정당한 엔지니어링 과제는 실패 문법이 안전하게 남는 최적화를 선택한 뒤, 선택된 경계가 실제로 적용 중임을 보여주는 증거를 보존하는 것입니다.

가장 강한 결론은 더 좁습니다. 과거의 성공은 예측을 개선할 수 있습니다. 다음 바이트가 어떻게 읽히게 될지를 결정하는 전환을 확인하는 것은, 현재 HTTP 버전과 현재 연결 상태 아래 해석된 현재 응답뿐입니다.

출처

  1. RFC 9931: Security Considerations for Optimistic Protocol Transitions in HTTP/1.1
  2. RFC 9931 RFC Editor 정보 페이지
  3. RFC 9110: HTTP Semantics
  4. RFC 9112: HTTP/1.1
  5. RFC 9298: Proxying UDP in HTTP
  6. RFC 6455: The WebSocket Protocol
  7. RFC 9484: Proxying IP in HTTP
  8. RFC 9113: HTTP/2
  9. RFC 9114: HTTP/3
  10. IANA HTTP Upgrade Token Registry
  11. Lu Heng, “The Policy Mirror”
  12. Lu Heng, “Minimum Initial Specification, Localized Future Decision, Voluntary Adoption”
  13. Lu Heng, “On Why BTW Media Exists, and Why Reality, Not Advocacy, Is the Product”