# HTTP/2.0 ## Overview - 지금 HTTP/1.1을 대부분 쓰고 있고, 회사 별로 HTTP/2.0을 쓰는 곳도 있는 상황 - 그래서 HTTP/2.0과 관련해서 HTTP/1.1과 주요 차이, 보안 이슈에 대해서 내용을 다룰 예정 ## Why HTTP/2.0? ### HTTP/1.1에서 개선 노력 - HTTP/1.1의 메시지 포맷은 구현의 단순성과 접근성에 주안점을 두고 최적화 - 커넥션 하나를 통해 요청 하나를 보내고 그에 대한 응답 하나만을 받는 방식 - 응답을 받아야만 다음 요청을 보낼 수 있기 때문에 회전 지연 발생(latency) - 이를 해결하기 위해서 병렬 커넥션, 파이프라인 커넥션이 도입되었지만 성능 개선에 대한 해결책이 되지는 못 함 - cf. [1부 4장 커넥션 관리 · Issue #4 · Effective-Java-Camp/http-the-definitive-guide · GitHub](https://github.com/Effective-Java-Camp/http-the-definitive-guide/issues/4) ### SPDY - 결국 성능 개선을 위해 WAKA, S+M 같은 프로토콜 등이 제안되었고, 구글에서 SPDY(스피디) 프로토콜을 개발 - SPDY 는 기존 HTTP t속도를 개선하기 위해 여러 기능이 추가된 것이고, HTTP를 대체하는 프로토콜이 아니라 HTTP가 전송 계층을 통해 전송되는 방식을 재정의하는 프로토콜 - 현재는 HTTP/2.0의 이점이 더 크기 때문에 크롬에서는 2016년에 SPDY 지원 기능을 제거 - HTTP/2.0 은 SPDY를 기반으로 설계 - cf. [SPDY - 위키백과, 우리 모두의백과사전](https://ko.wikipedia.org/wiki/SPDY) <br> ## HTTP/2.0  - HTTP/2.0은 TCP 커넥션 위에서 동작 - 요청과 응답은 길이가 정의된(최대 16383바이트) 한 개 이상의 프레임에 담기고, 헤더는 압축되어 담겨짐 - 프레임들에 담긴 요청과 응답은 스트림을 통해 보내지며, 한 개의 스트림이 한 쌍의 요청과 응답을 처리 - 하나의 커넥션 위에 여러 개의 스트림이 동시에 만들어 질 수 있으므로, 여러 개의 요청과 응답을 동시에 처리하는 것이 가능 - 서버 푸시 도입 (후술) - 하위 호환을 지원하기 위해 요청/응답 메시지의 의미를 HTTP/1.1과 같도록 유지 - ‘Content-Length’ 헤더는 HTTP/2.0에서 ‘:content-length’ <br> ## HTTP/1.1과 차이점 ### 프레임 - HTTP/2.0에서 모든 메시지는 프레임에 담겨 전송 <img width="495" alt="스크린샷 2022-09-04 오후 6 56 48" src="https://user-images.githubusercontent.com/59307414/188307900-bad386e2-0d2b-4c9a-9a7a-bbe42781e4c0.png"> - 프레임은 8바이트 크기의 헤더로 시작하고, 뒤이어 최대 16383바이트 크기의 페이로드가 옴 - R : 예약된 2비트 필드, 값의 의미가 정의되어 있지 않으며, 반드시 0이어야 함. 받는 쪽에서는 이 값을 무시 - 길이 : 페이로드의 길이를 나타내는 14비트, 길이에는 프레임 헤더는 포함되지 않음 - 종류 : 프레임의 종류를 나타내는 8비트 - 플래그 : 8비트 플래그 - R : 예약된 1비트 필드, 값의 의미가 정의되어 있지 않으며, 반드시 0이어야 함. 받는 쪽에서는 이 값을 무시 - 스트림 식별자 : 31비트 스트림 식별자, 0은 커넥션 전체와 연관된 프레임을 의미 - HTTP/2.0은 DATA, HEADERS, PRIORITY, RST_STREAM, SETTINGS, PISH_PROMISE, PING, GOAWAY, WINDOW_UPDATE, CONTINUATION라는 10가지 프레임을 정의 - cf. https://itchipmunk.tistory.com/272 <br> ### 스트림, 멀티플렉싱 - 스트림은 HTTP/2.0 커넥션을 통해 클라이언트와 서버 사이에서 교환되는 프레임들의 양방향 시퀀스 (하나 이상의 메시지 전달될 수 있음) - 한 쌍의 HTTP 요청과 응답은 하나의 스트림을 통해 이루어짐 ``` // HTTP/1.1 여러 요청을 보내는 flow 1. 한 TCP 커넥션을 통해 요청 전송 2. 응답이 도착할 때까지 대기 3. 응답 도착 후 다시 요청 ``` - 응답이 도착할 때까지 대기하기 때문에 지연 발생 - 이를 해결하기 위해서 여러 개의 TCP 커넥션 생성 -> 병렬 - 무작정 여러 커넥션을 만들 수 없기 때문에 파이프라인 커넥션 사용 - 다만 그다지 널리 구현되어 있지 않음 - HTTP/2.0에서는 하나의 커넥션에서 여러 개의 스트림을 동시에 열 수 있음 - 스트림에 우선순위를 부여할 수 있기 때문에 대역폭 제한이 있는 경우 중요한 리소스를 요청하는 스트림에 더 높은 우선순위를 부여 - 다만 우선순위를 따르는 것이 의무사항이 아니기 때문에 요청이 우선순위대로 처리된다는 보장은 없음 - HTTP/2.0 커넥션에서 한번 사용한 스트림 식별자는 다시 사용할 수 없음 - 커넥션을 오래 사용하다보면 스트림에 할당할 수 있는 식별자가 고갈되는 경우가 발생 -> 이 경우에는 다시 커넥션을 맺으면 됨 <br> ### 헤더 압축 - HTTP/1.1에서는 헤더는 아무런 압축 없이 그대로 전송 - 예전에는 헤더의 크기가 작았기 때문에 문제가 되지 않았지만 요즘은 하나의 웹페이지에서 많은 요청이 일어나기 때문에 헤더의 크기가 지연, 대역폭에 영향을 끼침 - 그래서 HTTP/2.0에서는 헤더를 압축하여 전송 - HPACK 명세에 정의된 헤더 압축 방법으로 압축 <br> ### 서버 푸시 - HTTP/2.0은 서버가 하나의 요청에 대해 응답으로 여러 개의 리소스를 보낼 수 있음 - 예를 들어 HTML을 요청 받은 서버는 함께 내려줘야 할 이미지, css, js 등의 리소스를 클라이언트에게 푸시할 수 있음 - 리소스를 푸시하려는 서버는 먼저 클라이언트에게 자원을 푸시할 것임을 `PUSH_PROMISE` 프레임을 보내어 미리 알려주어야 함 - 클라이언트가 별도로 요청하여 중복 요청되는 상황을 방지하기 위함 - 클라이언트가 `PUSH_PROMISE` 프레임을 받게 되면 해당 프레임의 스트림은 클라이언트 입장에서 `예약` 상태가 되고, 이 상태에서 클라이언트는 `RST_STREAM` 프레임을 전송해서 푸시를 거절할 수 있음 cf. https://freecontent.manning.com/animation-http-1-1-vs-http-2-vs-http-2-with-push/ <br> ## 보안 이슈 (Known issue) ### 중개자 캡슐화 공격 - HTTP/2.0 메시지를 프락시가 HTTP/1.1로 변환할 때 메시지의 의미가 변질될 수 있음 - HTTP/1.1과 달리 HTTP/2.0는 헤더 필드의 이름과 값을 바이너리로 인코딩 - 따라서 HTTP/2.0 헤더 필드는 어떤 문자열이든 사용할 수 있음 - 따라서 위조된 필드를 사용하여 공격할 수 있음 ### 긴 커넥션 유지로 인한 개인정보 누출 우려 - HTTP/2.0은 회전 지연을 줄이기 위해 오랫동안 커넥션을 지속 - 예를 들어 어떤 사용자가 브라우저를 사용할 때, 이전에 그 브라우저를 사용했던 사용자가 어떤 데이터를 주고 받았는지 알아낼 수 있음 - 현재 HTTP 커넥션도 동일한 문제를 가지고 있지만, 커넥션의 지속 기간이 짧기 때문에 상대적으로 위험이 덜함
HTTP/2.0
Overview
Why HTTP/2.0?
HTTP/1.1에서 개선 노력
SPDY
HTTP/2.0
HTTP/1.1과 차이점
프레임
프레임은 8바이트 크기의 헤더로 시작하고, 뒤이어 최대 16383바이트 크기의 페이로드가 옴
HTTP/2.0은 DATA, HEADERS, PRIORITY, RST_STREAM, SETTINGS, PISH_PROMISE, PING, GOAWAY, WINDOW_UPDATE, CONTINUATION라는 10가지 프레임을 정의
스트림, 멀티플렉싱
스트림은 HTTP/2.0 커넥션을 통해 클라이언트와 서버 사이에서 교환되는 프레임들의 양방향 시퀀스 (하나 이상의 메시지 전달될 수 있음)
HTTP/2.0에서는 하나의 커넥션에서 여러 개의 스트림을 동시에 열 수 있음
스트림에 우선순위를 부여할 수 있기 때문에 대역폭 제한이 있는 경우 중요한 리소스를 요청하는 스트림에 더 높은 우선순위를 부여
HTTP/2.0 커넥션에서 한번 사용한 스트림 식별자는 다시 사용할 수 없음
헤더 압축
서버 푸시
PUSH_PROMISE프레임을 보내어 미리 알려주어야 함PUSH_PROMISE프레임을 받게 되면 해당 프레임의 스트림은 클라이언트 입장에서예약상태가 되고, 이 상태에서 클라이언트는RST_STREAM프레임을 전송해서 푸시를 거절할 수 있음cf. https://freecontent.manning.com/animation-http-1-1-vs-http-2-vs-http-2-with-push/
보안 이슈 (Known issue)
중개자 캡슐화 공격
긴 커넥션 유지로 인한 개인정보 누출 우려