Microsoft MVP성태의 닷넷 이야기
웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c [링크 복사], [링크+제목 복사]
조회: 11046
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 4개 있습니다.)
웹: 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분
정성태

1  [2]  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13577정성태3/9/20241874닷넷: 2229. C# - 닷넷을 위한 난독화 도구 소개 (예: ConfuserEx)
13576정성태3/8/20241543닷넷: 2228. .NET Profiler - IMetaDataEmit2::DefineMethodSpec 사용법
13575정성태3/7/20241676닷넷: 2227. 최신 C# 문법을 .NET Framework 프로젝트에 쓸 수 있을까요?
13574정성태3/6/20241557닷넷: 2226. C# - "Docker Desktop for Windows" Container 환경에서의 IPv6 DualMode 소켓
13573정성태3/5/20241563닷넷: 2225. Windbg - dumasync로 분석하는 async/await 호출
13572정성태3/4/20241643닷넷: 2224. C# - WPF의 Dispatcher Queue로 알아보는 await 호출의 hang 현상파일 다운로드1
13571정성태3/1/20241621닷넷: 2223. C# - await 호출과 WPF의 Dispatcher Queue 동작 확인파일 다운로드1
13570정성태2/29/20241635닷넷: 2222. C# - WPF의 Dispatcher Queue 동작 확인파일 다운로드1
13569정성태2/28/20241545닷넷: 2221. C# - LoadContext, LoadFromContext 그리고 GAC파일 다운로드1
13568정성태2/27/20241606닷넷: 2220. C# - .NET Framework 프로세스의 LoaderOptimization 설정을 확인하는 방법파일 다운로드1
13567정성태2/27/20241618오류 유형: 898. .NET Framework 3.5 이하에서 mscoree.tlb 참조 시 System.BadImageFormatException파일 다운로드1
13566정성태2/27/20241631오류 유형: 897. Windows 7 SDK 설치 시 ".NET Development" 옵션이 비활성으로 선택이 안 되는 경우
13565정성태2/23/20241479닷넷: 2219. .NET CLR2 보안 모델에서의 개별 System.Security.Permissions 제어
13564정성태2/22/20241614Windows: 259. Hyper-V Generation 1 유형의 VM을 Generation 2 유형으로 바꾸는 방법
13563정성태2/21/20241646디버깅 기술: 196. windbg - async/await 비동기인 경우 메모리 덤프 분석의 어려움
13562정성태2/21/20241646오류 유형: 896. ASP.NET - .NET Framework 기본 예제에서 System.Web에 대한 System.IO.FileNotFoundException 예외 발생
13561정성태2/20/20241744닷넷: 2218. C# - (예를 들어, Socket) 비동기 I/O에 대한 await 호출 시 CancellationToken을 이용한 취소파일 다운로드1
13560정성태2/19/20241747디버깅 기술: 195. windbg 분석 사례 - Semaphore 잠금으로 인한 Hang 현상 (닷넷)
13559정성태2/19/20242625오류 유형: 895. ASP.NET - System.Security.SecurityException: 'Requested registry access is not allowed.'
13558정성태2/18/20241820닷넷: 2217. C# - 최댓값이 1인 SemaphoreSlim 보다 Mutex 또는 lock(obj)를 선택하는 것이 나은 이유
13557정성태2/18/20241621Windows: 258. Task Scheduler의 Author 속성 값을 변경하는 방법
13556정성태2/17/20241684Windows: 257. Windows - Symbolic (hard/soft) Link 및 Junction 차이점
13555정성태2/15/20241956닷넷: 2216. C# - SemaphoreSlim 사용 시 주의점
13554정성태2/15/20241709VS.NET IDE: 189. Visual Studio - 닷넷 소스코드 디컴파일 찾기가 안 될 때
13553정성태2/14/20241736닷넷: 2215. windbg - thin/fat lock 없이 동작하는 Monitor.Wait + Pulse
13552정성태2/13/20241693닷넷: 2214. windbg - Monitor.Enter의 thin lock과 fat lock
1  [2]  3  4  5  6  7  8  9  10  11  12  13  14  15  ...