인터넷 엔지니어링 태스크 포스 (IETF) P. McManus
Request for Comments: 8441 Mozilla
Updates: 6455 2018년 9월
카테고리: 표준 트랙
ISSN: 2070-1721

HTTP/2를 사용한 WebSockets 부트스트래핑


요약

이 문서는 WebSocket 프로토콜(RFC 6455)을 HTTP/2 연결의 단일 스트림에서 실행하기 위한 메커니즘을 정의합니다.

이 메모의 상태

이 문서는 인터넷 표준 트랙 문서입니다.

이 문서는 인터넷 엔지니어링 태스크 포스(IETF)의 산물입니다. 이 문서는 IETF 커뮤니티의 합의를 나타냅니다. 공개 검토를 거쳤으며 인터넷 엔지니어링 운영 그룹(IESG)의 출판 승인을 받았습니다. 인터넷 표준에 대한 추가 정보는 RFC 7841의 섹션 2에서 확인할 수 있습니다.

이 문서의 현재 상태, 정오표 및 이에 대한 피드백 제공 방법에 관한 정보는 https://www.rfc-editor.org/info/rfc8441에서 확인할 수 있습니다.

Copyright Notice

Copyright (c) 2018 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

1. 소개

The Hypertext Transfer Protocol (HTTP) [RFC7230] 은 서로 다른 버전 간에 리소스 수준의 호환되는 의미론을 제공하지만, 연결 관리 수준에서의 호환성은 제공하지 않습니다. WebSockets와 같이 HTTP의 연결 관리 세부사항에 의존하는 다른 프로토콜은 HTTP의 새로운 버전에 맞춰 업데이트되어야 합니다.

The WebSocket Protocol [RFC6455]는 HTTP/1.1의 Upgrade 메커니즘(섹션 6.7[RFC7230]) 을 사용하여 TCP 연결을 HTTP에서 WebSocket 연결로 전환합니다. HTTP/2([RFC7540])에서는 다른 접근 방식이 필요합니다. 멀티플렉싱 특성으로 인해 HTTP/2는 Upgrade 및 Connection 요청 헤더 필드나 101 (Switching Protocols) 응답 코드와 같은 연결 전체에 적용되는 헤더 필드나 상태 코드를 허용하지 않습니다. 이들은 모두 [RFC6455]의 오프닝 핸드셰이크에서 필요합니다.

HTTP/2에서 WebSockets를 부트스트랩할 수 있게 하면 하나의 TCP 연결을 두 프로토콜이 공유할 수 있고, HTTP/2의 더 효율적인 네트워크 사용을 WebSockets에도 확장할 수 있습니다.

이 문서는 RFC 7540 섹션 8.3에 명시된 HTTP/2용 CONNECT 메서드를 확장합니다. 이 확장은 CONNECT가 보통 외부 호스트에 연결하는 대신 연결할 새 프로토콜 이름을 대체할 수 있게 합니다. 그 결과 단일 HTTP/2 스트림 상의 터널이 생성되어 WebSockets(또는 다른 어떤 프로토콜)의 데이터를 운반할 수 있습니다. 연결의 다른 스트림들은 확장된 CONNECT 터널, 전통적인 HTTP/2 데이터 또는 둘의 혼합을 운반할 수 있습니다.

이 터널된 스트림은 연결의 다른 일반 스트림들과 멀티플렉스되며 HTTP/2의 일반적인 우선순위, 취소, 흐름 제어 기능을 누립니다.

이 문서에서 정의한 오프닝 핸드셰이크 수정을 사용하여 터널된 스트림으로 WebSocket 연결을 성공적으로 설정한 스트림들은 그 후 전통적인 WebSocket 프로토콜을 사용하며, 해당 스트림을 RFC 6455에서 언급된 TCP 연결인 것처럼 취급합니다.

2. 용어

이 문서에서 사용된 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 및 "OPTIONAL"이라는 핵심 단어들은 모두 대문자로 사용될 때에만 BCP 14(RFC2119), RFC8174에 설명된 대로 해석됩니다.

3. SETTINGS_ENABLE_CONNECT_PROTOCOL 설정 매개변수

이 문서는 [RFC7540]에서 정의된 설정들에 새로운 SETTINGS 매개변수를 추가합니다(섹션 6.5.2 참조).

새 매개변수 이름은 SETTINGS_ENABLE_CONNECT_PROTOCOL입니다. 이 매개변수의 값은 0 또는 1이어야 합니다.

값이 1인 SETTINGS_ENABLE_CONNECT_PROTOCOL을 수신하면, 클라이언트는 새로운 스트림을 생성할 때 이 문서에 정의된 확장된 CONNECT를 사용할 수 있습니다. 서버가 이 매개변수를 수신하더라도 아무 영향이 없습니다.

발신자는 이전에 1을 보낸 이후에 값을 0으로 설정된 SETTINGS_ENABLE_CONNECT_PROTOCOL 매개변수를 보내면 안 됩니다.

호환되지 않는 프로토콜 변경에 옵트인하기 위해 SETTINGS 매개변수를 사용하는 것은 RFC 7540 섹션 5.5가 정의한 "HTTP/2 확장"의 사용입니다. 특히 새로운 의사-헤더 필드 ":protocol"의 추가와 섹션 4에서의 :authority 의 의미 변경은 옵트인 협상을 필요로 합니다. 클라이언트가 SETTINGS_ENABLE_CONNECT_PROTOCOL 매개변수를 먼저 수신하지 않고 이 문서에 정의된 확장된 CONNECT 규정을 사용하면, 비지원 피어는 잘못된 요청으로 감지하고 스트림 오류를 생성할 것입니다(RFC 7540 섹션 8.1.2.6 참조).

4. 확장된 CONNECT 메서드

HTTP/2에서 CONNECT 메서드의 사용은 RFC 7540 섹션 8.3에 의해 정의됩니다. 이 확장은 메서드를 다음과 같이 수정합니다:

  • 요청 HEADERS에 새로운 의사-헤더 필드 :protocol을 포함시켜 CONNECT가 생성하는 터널에서 사용하려는 프로토콜을 표시할 수 있습니다. 이 의사-헤더 필드는 단일 값이며 <https://www.iana.org/assignments/http-upgrade-tokens/>에 있는 "HTTP Upgrade Token Registry"의 값 중 하나를 포함합니다.
  • :protocol 의사-헤더 필드를 포함하는 요청에서는 대상 URI의 :scheme 및 :path 의사-헤더 필드도 반드시 포함되어야 합니다(섹션 5 참조).
  • :protocol 의사-헤더 필드를 포함하는 요청에서는 :authority 의사-헤더 필드가 해당 문서의 RFC 7540 섹션 8.1.2.3의 해석을 따르며, 이는 이 확장으로 변경된 CONNECT가 사용되지 않은 경우의 섹션 8.3 해석과 다릅니다. 특히, 서버는 이 확장으로 수정되지 않은 CONNECT 요청과 같이 :authority가 가리키는 호스트로 터널을 생성하면 안 됩니다.

:protocol 의사-헤더 필드를 가진 CONNECT 요청을 수신하면, 서버는 의사-헤더 필드가 나타내는 프로토콜 유형의 다른 서비스로 터널을 확립합니다. 이 서비스는 서버와 동일한 장소에 있거나 없을 수도 있습니다.

5. 확장된 CONNECT를 사용하여 WebSocket 프로토콜 부트스트랩

:protocol 의사-헤더 필드는 CONNECT 요청에 반드시 포함되어야 하며, HTTP/2 스트림에서 WebSocket 연결을 시작하려면 값이 websocket이어야 합니다. 쿠키를 조작하는 등의 다른 HTTP 요청 및 응답 헤더 필드들은 평소처럼 CONNECT 메서드의 HEADERS에 포함될 수 있습니다. 이 요청은 [RFC6455]에서의 GET 기반 요청을 대체하며 WebSockets 오프닝 핸드셰이크를 처리하는 데 사용됩니다.

대상 URI의 스킴(RFC 7230 섹션 5.1)은 "wss" 스킴의 WebSockets에는 "https"여야 하고, "ws" 스킴의 WebSockets에는 "http"여야 합니다. 대상 URI의 나머지 부분은 WebSocket URI와 동일합니다. WebSocket URI는 여전히 프록시 자동 구성에 사용됩니다. 이 명세에서 사용되는 HTTP/2 연결의 보안 요구사항은 https 요청에 대해 [RFC7540]가 정하고, http 요청에 대해서는 [RFC8164]가 정합니다.

[RFC6455]는 HTTP/2의 일부가 아닌 Connection 및 Upgrade 헤더 필드의 사용을 요구합니다. 이들은 여기 정의된 CONNECT 요청에 포함되어서는 안 됩니다.

[RFC6455]는 또한 HTTP/2에 포함되지 않는 Host 헤더 필드의 사용을 요구합니다. 호스트 정보는 모든 HTTP/2 트랜잭션에서 요구되는 :authority 의사-헤더 필드의 일부로 전달됩니다.

확장된 CONNECT를 사용하여 WebSockets를 부트스트랩하는 구현체는 [RFC6455]의 Sec-WebSocket-Key와 Sec-WebSocket-Accept 헤더 필드의 처리를 수행하지 않습니다. 이러한 기능은 :protocol 의사-헤더 필드로 대체되었습니다.

Origin([RFC6454]), Sec-WebSocket-Version, Sec-WebSocket-Protocol, 및 Sec-WebSocket-Extensions 헤더 필드들은 [RFC6455]에서 정의된 대로 CONNECT 요청 및 응답 헤더 필드에서 사용됩니다. 참고로 HTTP/1의 헤더 필드 이름은 대소문자를 구분하지 않았던 반면, HTTP/2에서는 소문자로 인코딩되어야 합니다.

오프닝 핸드셰이크 처리가 성공한 후, 피어들은 CONNECT 트랜잭션의 HTTP/2 스트림을 RFC 6455에서 언급된 TCP 연결인 것처럼 취급하여 WebSocket 프로토콜을 진행해야 합니다. 이 시점에서 WebSocket 연결의 상태는 RFC 6455의 [RFC6455] 섹션 4.1에 정의된 바와 같이 OPEN입니다.

HTTP/2 스트림 종료는 또한 RFC 6455의 TCP 연결 종료에 준합니다. 정상적인 TCP 수준의 종료는 END_STREAM 플래그로 표현되며([RFC7540], 섹션 6.1 참조), RST 예외는 RST_STREAM 프레임([RFC7540], 섹션 6.4)의 CANCEL 오류 코드로 표현됩니다.

5.1. 예시

[[ From Client ]]                       [[ From Server ]]

                                        SETTINGS
                                        SETTINGS_ENABLE_CONNECT_[..] = 1

HEADERS + END_HEADERS
:method = CONNECT
:protocol = websocket
:scheme = https
:path = /chat
:authority = server.example.com
sec-websocket-protocol = chat, superchat
sec-websocket-extensions = permessage-deflate
sec-websocket-version = 13
origin = http://www.example.com

                                        HEADERS + END_HEADERS
                                        :status = 200
                                        sec-websocket-protocol = chat

DATA
WebSocket Data

                                        DATA + END_STREAM
                                        WebSocket Data

DATA + END_STREAM
WebSocket Data

6. 설계 고려사항

HTTP/2에 보다 네이티브하게 통합하려면 HTTP/2에 더 큰 변경을 가할 수도 있었습니다. 이 설계는 솔루션 복잡성을 최소화하면서 HTTP/2와 WebSockets를 동시에 실행하는 주요 문제를 해결하도록 선택되었습니다.

7. 중계자에 관하여

이 문서는 WebSockets가 HTTP 포워드 프록시와 상호작용하는 방식을 변경하지 않습니다. WebSockets를 사용하려는 클라이언트가 HTTP/2를 통해 HTTP 프록시에 연결하는 경우, 그 프록시를 통해 WebSocket 서버로 터널링하려면 전통적인 CONNECT(즉, :protocol 의사-헤더 필드 없이)를 계속 사용해야 합니다.

해당 터널에서 사용되는 HTTP 버전은 WebSockets가 직접 시작되는지 아니면 이 문서에 설명된 수정된 CONNECT 요청을 통해 시작되는지를 결정합니다.

8. 보안 고려사항

[RFC6455]는 특히 XMLHttpRequest 기반 클라이언트와 같은 비-WebSockets 클라이언트가 WebSocket 연결을 만들지 못하도록 보장합니다. 이를 위한 주요 메커니즘은 XMLHttpRequest 기반 클라이언트가 생성할 수 없는 Sec- 접두사의 요청 헤더 필드 사용입니다. 이 명세는 두 가지 방식으로 해당 문제를 다룹니다:

  • XMLHttpRequest는 Sec- 접두사 요청 헤더 필드 외에도 CONNECT 메서드의 사용을 금지합니다.
  • 의사-헤더 필드의 사용은 연결에 특정한 것으로, HTTP/2는 프로토콜 스택 외부에서 의사-헤더를 생성하는 것을 허용하지 않습니다.

[RFC6455]의 보안 고려사항들(섹션 10)은 이 명세를 사용하여 WebSocket 프로토콜을 사용할 때 계속 적용됩니다. 단, 이 문서에서 변경된 부트스트랩 핸드셰이크와 관련된 섹션(10.8)은 관련이 없습니다.

9. IANA 고려사항

9.1. 새 HTTP/2 설정

이 문서는 RFC 7540 섹션 11.3에서 설정된 "HTTP/2 Settings" 레지스트리에 항목을 등록합니다.

Code:
0x8
Name:
SETTINGS_ENABLE_CONNECT_PROTOCOL
Initial Value:
0
Specification:
이 문서

9.2. 새 HTTP 업그레이드 토큰

이 문서는 [RFC7230]에서 설정된 "HTTP Upgrade Tokens" 레지스트리에 항목을 등록합니다.

Value:
websocket
Description:
The Web Socket Protocol
Expected Version Tokens:
 
References:
[RFC6455] [RFC8441]

감사의 말

2017년 HTTP 워크숍에서는 핵심 문제와 허용 가능한 해결 복잡도를 결정하는 데 도움이 된 매우 생산적인 논의가 있었습니다.

저자 연락처

Patrick McManus
Mozilla
EMail: mcmanus@ducksong.com