Microsoft MVP성태의 닷넷 이야기
웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c [링크 복사], [링크+제목 복사],
조회: 19357
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 5개 있습니다.)
개발 환경 구성: 361. Azure Web App(App Service)의 HTTP/2 프로토콜 지원
; https://www.sysnet.pe.kr/2/0/11493

웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c
; https://www.sysnet.pe.kr/2/0/12495

.NET Framework: 1014. ASP.NET Core(Kestrel)의 HTTP/2 지원 여부
; https://www.sysnet.pe.kr/2/0/12500

.NET Framework: 1015. .NET 5부터 HTTP/1.1, 2.0 선택을 위한 HttpVersionPolicy 동작 방식
; https://www.sysnet.pe.kr/2/0/12501

.NET Framework: 1016. .NET Core HttpClient의 HTTP/2 지원
; https://www.sysnet.pe.kr/2/0/12502




IIS의 HTTP/2 지원 여부 - h2, h2c

우선 h2, h2c에 대한 용어부터 정리해야겠습니다. ^^

글을 읽다 보면, 간혹 HTTP/1.1을 h1, HTTP/2.0을 h2로 표기하는 것을 보게 됩니다. 사실 이게 엄밀히 말해서, 그냥 줄여서 표현하기 위해 그런 것인지 공식적으로 저 명칭이 있는 것인지는 잘 모르겠습니다. 가령 HTTP/1.1 RFC 문서에서는,

Hypertext Transfer Protocol -- HTTP/1.1
; https://tools.ietf.org/html/rfc2616

"h1"이라는 단어 자체가 없습니다. 따라서, 아마도 문맥에 따라 h1을 기존의 HTTP/1.1로 이해하는 것이 맞을 수 있습니다. (혹시 이에 대한 이력을 알고 계신 분은 덧글 부탁드립니다. ^^)

그런데, h2의 경우에는 좀 다릅니다. HTTP/2 공식 문서에는,

Hypertext Transfer Protocol Version 2 (HTTP/2)
; https://tools.ietf.org/html/rfc7540
; https://httpwg.org/specs/rfc7540.html

분명히 버전 식별자로써 이에 대한 설명이 있습니다.

3.1.  HTTP/2 Version Identification

   The protocol defined in this document has two identifiers.

   o  The string "h2" identifies the protocol where HTTP/2 uses
      Transport Layer Security (TLS) [TLS12].  This identifier is used
      in the TLS application-layer protocol negotiation (ALPN) extension
      [TLS-ALPN] field and in any place where HTTP/2 over TLS is
      identified.

      The "h2" string is serialized into an ALPN protocol identifier as
      the two-octet sequence: 0x68, 0x32.

즉, (문맥에 따라 줄임말일 수 있지만) HTTP/2에 대한 줄임말로서의 "h2"가 아니라, TLS 통신과 함께 그것의 ALPN 확장이 쌍을 이뤄 사용하는 HTTP/2의 프로토콜 식별자입니다. 그리고, TLS를 사용하지 않는 일반 평문 통신에서 HTTP/2의 프로토콜 식별자를 의미하는 h2c가 있습니다. (h2c의 c는 cleartext를 의미합니다.)

   o  The string "h2c" identifies the protocol where HTTP/2 is run over
      cleartext TCP.  This identifier is used in the HTTP/1.1 Upgrade
      header field and in any place where HTTP/2 over TCP is identified.

      The "h2c" string is reserved from the ALPN identifier space but
      describes a protocol that does not use TLS.

즉, 간단하게 정리하면 h2는 https 위에서, h2c는 http 위에서 동작하는 HTTP/2.0에 대한 프로토콜 식별자인 것입니다.




h2, h2c를 이야기할 때 언급해야 할 것이 또 하나 있다면 바로 "협상"입니다. 웹 브라우저 입장에서는 서버 측에서 HTTP/2 프로토콜을 제공하지 않는다면 HTTP/1.1로도 통신이 가능하게 만들어야 하므로 서버가 HTTP/2를 구현하고 있는지 알아내는 과정이 필요합니다.

우선, h2의 경우에는 어차피 TLS 협상이 필요하기 때문에 이 과정에 얹어서 함께 진행되므로 별도의 협상 과정이 필요 없습니다. 반면, h2c의 경우에는 다릅니다. http:// 통신은 소켓 연결 후 곧바로 HTTP 헤더를 보내 통신을 게시하므로 처음부터 HTTP/2 통신을 진행할 수는 없고 일단 HTTP/1.1 요청을 보낸 후 서버의 응답 결과에 따라 이후 HTTP/2 통신을 게시합니다. 이에 대해서는 RFC7540 문서에서 명시하고 있는데, 우선 웹 브라우저는 다음의 요청을 서버에 보내고,

GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>

만약 서버가 HTTP/2를 지원하지 않는다면 응답 헤더에 "Upgrade" 헤더를 포함하지 않는 식으로 클라이언트에 GET 요청에 따른 리소스와 함께 응답합니다.

HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html

...

결국 HTTP/1.1의 요청과 응답으로 이뤄지기 때문에 기존 HTTP/1.1 통신의 입장에서는 협상에 따른 별도의 부하가 발생하는 것은 아닙니다.

반면, 만약 HTTP/2.0을 지원한다면 프로토콜 스위치를 위한 "Upgrade: h2c" 헤더를 함께 응답에 추가하고,

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

[ HTTP/2 connection ...]

이후부터는 자연스럽게 HTTP/2.0 규약에 맞게 통신을 지속합니다. 즉, 협상을 한다고 해도 첫 번째 요청에 대해서만 HTTP/1.1 통신을 하는 것일 뿐 이후의 통신 과정은 HTTP/2.0을 따르므로 마찬가지로 협상으로 인한 부하가 발생하는 것은 아닙니다.

또한, h2c 방식에서도 저렇게 협상을 하지 않고 곧바로 HTTP/2.0 규격으로 통신을 게시할 수 있습니다. (당연히, 이런 경우에는 HTTP/2.0을 지원하지 않는 서버와는 정상적인 통신을 하지 못합니다.)




자, 그럼 실제로 저 차이점들을 간단하게 curl.exe를 이용해 확인해 볼까요? ^^ (윈도우 사용자는 WSL2 환경의 리눅스에 있는 curl을 권장합니다.)

서버는 잘 알려진 nghttp2.org를 이용할 수 있으므로, 다음은 h2c + 협상을 이용해 HTTP/2 통신을 한 결과를 보여줍니다.

$ curl --http2 -I nghttp2.org
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

HTTP/2 200
date: Sat, 16 Jan 2021 06:42:43 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.002868
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

반면, 협상 없이 무조건 HTTP/2 프로토콜로 h2c 통신을 하려면 이렇게 옵션을 추가하면 됩니다.

$ curl --http2-prior-knowledge -I nghttp2.org
HTTP/2 200
date: Sat, 16 Jan 2021 06:42:56 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.00316
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

마지막으로, h2 통신을 실습해 보면,

$ curl --http2 -I https://nghttp2.org
HTTP/2 200
date: Sat, 16 Jan 2021 07:03:19 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.004217
strict-transport-security: max-age=31536000
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

// 어차피 TLS 협상이므로 굳이 --http2 옵션을 주지 않아도 https 접근 시에 h2를 설정하는 듯합니다.
$ curl -I https://nghttp2.org
HTTP/2 200
date: Sat, 16 Jan 2021 07:04:32 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.001008
strict-transport-security: max-age=31536000
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

"https"로 인해 TLS 협상이 이뤄지고 결국 h2c 테스트의 --http2-prior-knowledge 옵션과 동일하게 별도의 "101 Switching Protocols" 과정 없이 진행된 것을 확인할 수 있습니다.




자, 길고 긴 서문을 지나서 이제야 제목에 맞는 글을 쓰게 되는군요. ^^

우선, 공식 문서를 보면,

HTTP/2 on IIS
; https://learn.microsoft.com/en-us/iis/get-started/whats-new-in-iis-10/http2-on-iis

Windows 10의 경우 1607 버전, Windows Server의 경우에는 2016 버전에 탑재된 IIS 10.0부터 HTTP/2를 지원하며, 이와 함께 다음의 제약이 있다고 합니다.

  • Windows authentication (NTLM/Kerberos/Negotiate) is not supported with HTTP/2. In this case IIS will fall back to HTTP/1.1.
  • Clear text - as mentioned above, IIS currently only supports HTTP/2 over TLS. Again, IIS will fall back to HTTP/1.1.
  • Bandwidth throttling - IIS has a feature to limit bandwidth (in Inetmgr, select the site, 'Limits' under Configure of the Action pane). This applies to HTTP/1.1 but is not enforced for HTTP/2 (will proceed with no errors or bandwidth limiting).

음... h2c 방식은 지원하지 않는다는 건데, 그래도 최신 버전인 Windows 10의 20H2 업데이트(버전 19042)에 있는 IIS는 뭔가 달라질 수도 있으니 nghttp2.org에 했던 것과 유사하게 테스트를 해보겠습니다. 우선 가장 궁금한 h2c, 즉 평문으로 HTTP/2.0 통신이 가능한지 이렇게 명령을 내리면,

/*
IIS 서버 IP: 210.91.106.100
*/

$ curl --http2-prior-knowledge -I http://210.91.106.100
curl: (16) Error in the HTTP2 framing layer

지원을 안 하는군요. ^^ 그래도 --http2 옵션을 지정하면 협상을 진행하기 때문에 HTTP/1.1로 통신이 진행됩니다.

$ curl --http2 -I http://210.91.106.100
HTTP/1.1 200 OK
Content-Length: 696
Content-Type: text/html
Last-Modified: Fri, 12 Jun 2020 04:28:37 GMT
Accept-Ranges: bytes
ETag: "38365f17140d61:0"
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Sat, 16 Jan 2021 08:08:27 GMT

물론, (문서에 명시했으므로 당연하겠지만) h2 방식은 지원합니다.

/*
https 인증서: 테스트 인증서를 사용했으므로 curl에 -k 옵션 추가
*/

$ curl --http2 -k -I https://210.91.106.100
HTTP/2 200
content-length: 696
content-type: text/html
last-modified: Fri, 12 Jun 2020 04:28:37 GMT
accept-ranges: bytes
etag: "38365f17140d61:0"
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET
date: Sat, 16 Jan 2021 08:06:54 GMT

$ curl -k -I https://210.91.106.100
HTTP/2 200
content-length: 696
content-type: text/html
last-modified: Fri, 12 Jun 2020 04:28:37 GMT
accept-ranges: bytes
etag: "38365f17140d61:0"
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET
date: Sat, 16 Jan 2021 08:06:58 GMT




참고로 아래의 글에 나온,

I get the message: "Cant connect securely to this page. This might be because the site uses outdated or unsafe TLS security settings.
; https://learn.microsoft.com/en-us/windows-server/manage/windows-admin-center/support/troubleshooting#i-get-the-message-cant-connect-securely-to-this-page-this-might-be-because-the-site-uses-outdated-or-unsafe-tls-security-settings

EnableHttp2Tls REG_DWORD 0
EnableHttp2Cleartext REG_DWORD 0

EnableHttp2Cleartext를 1로 설정해봤으나, h2c는 여전히 안 됩니다. 일단, 공식 문서 상으로 h2c에 대한 언급이 없으니 IIS에서는 안 되는 게 맞습니다. ^^

그 외에, 간혹 보면 HTTP/2를 활성화하기 위해 DuoEnabled 레지스트리 키를 설정하라는 글이 나오는데,

Microsoft IIS 10.0 - Installing HTTP/2 on IIS 10.0
; https://devopspoints.com/microsoft-iis-10-0-installing-http-2-on-iis-10-0-999.html

이것은 Windows 10 CTP 버전에 한해서이고, 현재의 버전에서는 해당 레지스트리 설정이 아무런 역할을 하지 않습니다.




Windows 10 사용자의 경우, (Windows 10 1803 빌드부터 기본 포함되어 있기도 한) curl.exe를 사용해 --http2 옵션을 테스트하면 다음과 같은 오류가 발생합니다.

C:\temp> curl --http2 -I https://nghttp2.org
curl: (1) Unsupported protocol

C:\temp> curl --version
curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
Release-Date: 2017-11-14, security patched: 2019-11-05
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL

이에 대해서는 이미 알려져 있는데,

Curl shipped with Windows does not support HTTP2 #3141
; https://github.com/microsoft/WSL/issues/3141

"curl --version"의 출력 결과에 "nghttp2" 문구가 있는 버전을 사용해야 합니다. 따라서 별도로 다른 도구와 설치된 curl.exe를 사용하거나, (약간 불안하지만 지원이 되도록 빌드한) 바이너리를 다운로드하거나, 또는 직접 빌드하거나 셋 중 하나를 선택하면 됩니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/28/2023]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2021-01-22 07시31분
정성태

... 166  167  168  169  [170]  171  172  173  174  175  176  177  178  179  180  ...
NoWriterDateCnt.TitleFile(s)
764정성태8/21/200922951Windows: 47. Windows Virtual PC에 설치된 Windows 7 VPC에서 Aero 효과 사용 [3]
763정성태8/20/200926532Windows: 46. Windows 7 - XP 모드 응용 프로그램 바로가기 만드는 방법 [2]
762정성태8/18/200932157개발 환경 구성: 48. 개발자 PC 환경 - 유니코드(Unicode)를 위한 설정 [3]
760정성태8/17/200938514개발 환경 구성: 47. XmlCodeGenerator 1.0.0.4 업데이트 [2]
759정성태8/16/200930367.NET Framework: 155. 닷넷 프로파일러의 또 다른 응용: Visual Studio 2010 Historical Debugging
758정성태8/15/200923708VS.NET IDE: 65. WPF 프로젝트용 Visual Studio 패치들 [2]
757정성태8/12/200923117오류 유형: 84. TFS 작업 항목 보기 오류 - WorkItemTypeDeniedOrNotExistException
756정성태8/9/200922703오류 유형: 83. A revocation check could not be performed for the certificate.
755정성태8/6/200920461.NET Framework: 154. 이벤트 2중 구독
754정성태7/16/200932798VS.NET IDE: 64. Visual Studio 2010 - 64bit 혼합 모드 디버깅 지원
753정성태7/15/200931322.NET Framework: 153. WPF와 WinForm의 Shown 이벤트 시점
752정성태7/14/200926901개발 환경 구성: 46. .NET Service Bus 응용 사례: SocketShifter [2]파일 다운로드1
751정성태7/9/200928221.NET Framework: 152. 순환 참조와 XmlSerializer파일 다운로드1
750정성태7/7/200927984.NET Framework: 151. Team Explorer가 설치되지 않은 PC에서 System.InvalidProgramException 예외 발생파일 다운로드1
748정성태7/2/200925824.NET Framework: 150. WPF - Property Element 사용 의미파일 다운로드2
747정성태7/1/200945522.NET Framework: 149. WPF - UI 업데이트를 바로 반영하고 싶다면? [3]파일 다운로드1
746정성태6/25/200932654.NET Framework: 148. WPF - 데이터 바인딩 시의 예외 처리 방법 [1]파일 다운로드1
745정성태6/22/200924663.NET Framework: 147. WPF - Binding에 Sibling 요소 지정 [2]파일 다운로드1
744정성태6/21/200923522.NET Framework: 146. WPF - 중첩된 ScrollViewer의 크기 제어 [2]파일 다운로드1
743정성태6/17/200927578.NET Framework: 145. Unity Container 개체 풀이
742정성태6/17/200927049.NET Framework: 144. WPF - FrameworkElement.Parent 속성이 null이라면? [3]
740정성태6/12/200924647.NET Framework: 143. WPF - Transform의 역변환파일 다운로드1
739정성태6/8/200937389.NET Framework: 142. WPF - Grid 컨트롤의 ShowGridLine 개선 [5]파일 다운로드1
737정성태6/6/200942874.NET Framework: 141. Win32 Interop - 크기가 정해지지 않은 배열을 C++에서 C#으로 전달하는 경우파일 다운로드2
734정성태6/4/200926291.NET Framework: 140. WPF - CellPadding 속성을 구현하는 Grid Layout [2]파일 다운로드1
733정성태5/29/200931674.NET Framework: 139. WPF - "M/d/yyyy h:mm:ss tt" 형식으로만 날짜를 출력하는 문제
... 166  167  168  169  [170]  171  172  173  174  175  176  177  178  179  180  ...