HTTP/2.0 등장 배경
- HTTP/1.1의 메시지 포맷은 구현의 단순성과 접근성에 요점을 두고 최적화 되었다. 그러다보니 성능은 어느 정도 희생할 수 밖에 없었다. 하나의 요청과 응답만 주고받을 수 있어서 심각한 회전 지연 발생.
- 이를 해결하기 위해 병렬 커넥션이나 파이프라인 커넥션이 도입되었지만 근본적인 문제를 해결하진 못했음.
- 2009년, 구글은 기존의 HTTP의 속도를 개선하기 위해 빠르다는 의미로 SPDY라는 프로토콜을 개발함.
- 2012년 10월 3일, HTTP작업 그룹은 SPDY를 기반으로 HTTP/2.0 프로토콜을 설계하기로 결정.
SPDY?
- 헤더를 압축하여 대역폭을 절약.
- 하나의 TCP커넥션에 여러 요청을 동시에 보내 회전 지연을 줄이는 것이 가능해짐.
- 클라이언트가 요청을 보내지 않아도 서버가 능동적으로 필요한 리소스를 푸시하는 기능도 있음.
🤷 무엇이 차이가 있을까?
스트림과 멀티플렉싱
- 스트림: HTTP/2.0 커넥션을 통해 교환되는 프레임들의 독립된 양방향 시퀀스. (데이터 덩어리)
- HTTP/1.1은 TCP 커넥션이 연결되면 하나의 요청을 전송하고 응답이 오면 커넥션이 닫힌다. 이러한 과정이 계속 반복되다 보니 트래픽이 급증하기 시작함.
- 하지만 HTTP/2.0은 하나의 커넥션에서 여러 개의 스트림이 동시에 열릴 수 있음.
- 스트림은 우선순위를 가질 수 있다는 특징이 있음.
- 하지만 의무사항이 아니기 때문에 요청이 우선순위대로 처리된다는 보장은 없음.
헤더 압축
- 요즘엔 헤더가 무지하게(?) 많기 때문에 그대로 보내면 트래픽 급증과 회전 지연이 발생함. 때문에 헤더를 압축해서 전송함.
- 압축한 뒤, 헤더 블록 조각으로 나눠서 전송됨. 받은 쪽에서는 이 조각들을 다받고 이어맞춘 뒤 복원함.
- HPACK(헤더압축양식)은 헤더를 압축하고 해제할 때 압축 콘텍스트라는 것을 사용함.
- 압축 콘텍스트는 헤더의 압축을 풀 때 영향을 받아 모습이 바뀌어버림.
- 그래서 송신한 측은 수신쪽의 압축 콘텍스트가 바뀌었을 거라고 예측을 하고 그에 맞는 대비를 함.
→ 그래서 어떤 경우에도 헤더를 받을 경우 압축 해제를 수행해야 함.
- 만약 헤더 압축 해제를 못할 경우, 커넥션을 끊어야 함.
서버 푸시
- HTTP/2.0은 클라이언트가 HTML파일을 요청했는데 서버는 이에 관련된 CSS, JS파일 리소스도 보내줌.
→ 이는 클라이언트가 다시 요청해여 발생될 트래픽을 방지해준다.
- 그래서 서버는 PUSH_PROMISE라는 것을 보내며 미리 말해준다.
→ "나 이거 보낼거니까 같은거 요청하지마~" 라는 뜻.
- 이 상태에서 클라이언트는 RST_STREAM 프레임을 보내서 추가적인 리소스를 거절할 수 있음.
- 서버는 오직 안전하고 캐시 가능하고 본문을 포함하지 않은 요청에 대해서만 푸시 가능.
- 서버 푸시를 끄고 싶다면 settings_push를 0으로 설정하면 됨.
- 서버 푸시를 사용했더라도 중간에 프록시가 서버로부터 받은 추가 리소스를 클라이언트에게 안줄 수도 있음. (반대의 경우도 있음)
❗️알려진 보안 이슈
중개자 캡슐화 공격
- HTTP/2.0 메시지를 중간에 HTTP/1.1로 변경할 때 의미가 변질될 가능성이 있음.
- HTTP/2.0은 헤더필드의 값을 바이너리 값으로 인코딩해서 어떤 프로토콜이든 사용할 수 있게 만들어줌.
- 그래서 불법적이거나 위조된 HTTP/1.1메시지로 번역될 가능성이 있다.
- 반대로 1.1에서 2.0으로 번역하는 과정에 이러한 경우는 없음.
긴 커넥션 유지로 인한 개인정보 누출 우려
- HTTP/2.0은 커넥션 회전 지연을 줄이기 위해 클라이언트와 서버사이를 오래 유지하는 경향이 있음.
- 이러한 경우엔 개인정보가 유출될 가능성이 있음.
Reference