우클릭방지

글 목록

레이블이 HTTP인 게시물을 표시합니다. 모든 게시물 표시
레이블이 HTTP인 게시물을 표시합니다. 모든 게시물 표시

2023년 7월 10일 월요일

[사용자 IP 정보] X-Forwarded-For, Forwarded, Proxy Protocol

클라이언트 IP 정보가 필요한 이유


오늘날 많은 기업들이 클라우드 환경으로 자신의 인프라 환경을 이전하거나 이전을 고민하고 있다. 

오늘은 인프라 환경 이전에 고려할 만한 내용인 로드밸런서와 사용자 IP 확인에 대한 이야기를 해본다. 


온프레미스 환경에서 로드밸런서의 역할은 매우 중요했다. 

로드밸런서는 서버의 트래픽 분산을 통해 많은 사용자들의 접속을 가능케 했으며, 다양한 분산 기능과 분산 알고리즘을 통해 보안 제품들을 인프라에 효과적으로 적용하였다. 

클라우드 환경에서 역시 로드밸런서의 역할은 중요한 기능 중의 하나이며, 대부분의 CSP (Cloud Service Provider) 는 이를 기본 서비스로 제공한다. 


하지만 클라우드 환경에서 제공하는 로드밸런서는 온프레미스 환경의 로드밸런서와 약간 차이가 있다. 프록시 기술을 기반으로 제공하다 보니 로드밸런서를 통해 서버로 유입되는 트래픽에서 사용자의 IP 나 포트 정보를 추출하기가 힘들어졌다. 

로드밸런서를 거치면 사용자 IP 가 로드밸런서 자체 IP로 변경되기 때문이다.


애플리케이션 서버, 그리고 서버로 전달되기 전 경유하는 보안 제품들 입장에서 사용자 IP 정보는 중요하다. 


클라이언트 IP 정보를 추출하는 방법


이제 클라우드 환경에서 사용자 정보를 얻는 방법에 대해 본격적으로 이야기 해 보자.  


사용자 IP 정보 추출의 어려움이 클라우드 환경에서 가지는 특징이라고 하지만, 그렇다면 사용자 정보를 얻을 수 있는 방법은 없을까?

당연히 이런 고민들을 많은 사람들이 했고 이에 대한 방안 역시 준비가 되어 있다. 


방법부터 말하자면 아래와 같이 3 가지가 있다. 

  1. X-Forwarded-For

  2. Forwarded

  3. Proxy Protocol


참고로 아래 테스트 환경은 다음과 그림과 같다.




X-Frowarded-For


먼저 X-Forwarded-For 부터 알아보자. 

XFF 라고 불리는 이 방법은 HTTP 요청 헤더에 사용자 정보를 담아 보내는 방법이다. 

Squid 라고 하는 오픈 소스 프록시 제품에서 먼저 사용한 방법인데 이 무료 제품이 너무 유명해 지다 보니 자연스레 XFF가 널리 사용된 케이스 이다. 

하지만, 표준처럼 인식되고 있는 이 XFF 헤더는 공교롭게도 표준이 아니다. 

필자는 2000년 중반 직장 생활의 시작을 INKTOMI(잉크토미) 라고 하는 프록시 서버의 일종인 캐시서버 제품을 지원하는 엔지니어였다보니 XFF 를 아주 잘 알고 있었으나 표준으로 알고 있는 분들이 의외로 많이 있는 것 같다. 


XFF 는 프록시가 실제 애플리케이션 서버와 TCP 세션 수립 이후 HTTP 요청을 보낼 때 X-Forwarded-For 라는 헤더에 실제 사용자 IP 정보를 담아 전달한다. 

헤더는 아래와 같이 다중 값을 가질 수 있다. 


X-Forwarded-For: client, proxy1, proxy2


프록시 서버를 거치는 순서대로 Value 가 추가되니 제일 처음의 IP 정보를 실제 사용자 정보로 보면 된다. 다른 의미로는 제일 마지막 Value 는 애플리케이션 서버와 가장 가까운 위치에 있는 프록시로 해석할 수도 있겠다. 


실제 패킷 내용은 다음과 같다. 

[ Wireshark 패킷 내용 ]

[ Wireshark 패킷 내용을 Stream 조합한 내용 ]



애플리케이션 서버에서는 IP 헤더의 소스 IP 정보 대신 XFF 헤더 정보를 파싱하여 접속 내용을 기록하면 된다. 



Forwarded


Forwarded 헤더는 위에서 설명한 XFF 의 Standard 버젼으로 보면 된다. 

XFF 와 같이 콤마(,) 로 분리된 다중 값을 가질수 있다. 


Forwarded: for=client, for=proxy1, for=proxy2


헤더의 구조는 XFF 와 거의 비슷하기 때문에 따로 설명을 자세히 하진 않는다. 

XFF와 비슷해서이기도 하지만, 실제 현장에서 XFF 가 99.9% 로 사용되기 때문이다. 



Proxy Protocol


위에서 설명했던 XFF 와 Fowraded 헤더는 HTTP 헤더의 한 종류이다. 다시 말해서 HTTP 기반의 서비스여야만 프록시를 통한 접속에서 사용자 정보를 확인할 수 있다.

그럼 HTTP 서비스가 아니라면 사용자 정보를 확인 할 수 있는 방법이 없을까?

이를 해결해 줄 수 있는 것이 바로 Proxy Protocol 이다. 

프록시 프로토콜은 TCP 기반에서 사용되는 옵션이라 TCP 기반의 어느 서비스에서나 이를 이용하여 사용자 정보를 확인 할 수 있다. 

Proxy Protocol 의 포맷은 아래와 같다. 

PROXY <protocol> <srcip> <dstip> <srcport> <dstport>\r\n


실제 패킷에서 내용을 확인하면 아래와 같은데, HTTP 요청헤더가 전달되기 전에 Proxy Protocol 이 선행 됨을 확인할 수 있다. 



[ Wireshark 패킷 내용 ]



[ Wireshark 패킷 내용을 Stream 조합한 내용 ]




상황별 웹서버 Access 로그 내용


아래는 nginx 웹서버의 접근로그(access.log) 포맷이다. 


사용자 IP($remote_addr), XFF 정보 ($http_x_forwarded_for), Proxy Protocol 정보 ($proxy_protocol_addr) 정보 순으로 IP 정보를 남기게 로그 포맷을 수정하였다.



상황 1. 클라이언트가 직접 웹서버로 접속한 경우

  • 사용자 IP : 192.168.212.180



사용자가 프록시를 통하지 않고 웹서버로 직접 접속하는 경우이니 웹서버에서 사용자 IP 정보를 바로 확인할 수 있다.

[ 웹서버의 Access 로그 ]


상황 2. 클라이언트 정보 전달 관련련 어떤 설정도 하지 않은 경우

  • 프록시 IP : 172.16.1.115
프록시를 통해 접속이 되므로, 프록시에서 사용자 IP 를 전달해 주는 기능이 없는 경우 웹서버에서는 사용자 IP 정보를 확인할 방법이 없다.

[ 웹서버의 Access 로그 ]



상황 3. XFF 설정을 한 경우

  • 사용자 IP : 192.168.212.180,
  • 프록시 IP : ;172.16.1.115

프록시가 XFF 기능을 이용해 사용자 IP 정보를 전달한 경우 아래와 같이 사용자 IP (192.168.212.180) 을 접속로그에서 확인할 수 있다.

[ 웹서버의 Access 로그 ]


상황 4. XFF 와 Proxy Protocol 설정을 한 경우

  • 사용자 IP : 192.168.212.180,
  • 프록시 IP : ;172.16.1.115


프록시가 XFF 와 Proxy Protocol 을 모두 제공하는 경우이다. 웹서버의 접근로그에서 설정한 것과 같이 IP 헤더의 소스 IP, XFF 정보, Proxy Protocol 정보 순으로 기록되어 있는 것을 확인할 수 있다.


[ 웹서버의 Access 로그 ]


끝~



2022년 11월 25일 금요일

[API 보안] #1. API 기술이 관심을 받게 된 배경

2007년 미국의 스티브잡스는 전세계에 IT 환경의 큰 변화를 일으킬 대단한 시도를 했다. 
바로 아이폰 출시~

[ 이미지 출처 : https://hub.zum.com/enjoiyourlife/10535 ]


전세계의 인류의 휴대폰 사용 환경이 정말 거짓말처럼 빠른 시간 안에 변하게 된다.

아이폰 출시 이전까지는 휴대폰은 단순히 사람과 사람을 연결 시켜 주는 통신 수단의 역할만 했다. 전화, 텍스트 메시지.. 

하지만 아이폰은 휴대폰의 역할을 삶의 중요한 디바이스 이상으로 바꿨으며, 모든 생활이 휴대폰을 중심으로 만들어 진다 해도 과언이 아닐 정도로 변화 시켰다. 

가장 큰 변화는 인터넷 사용 환경을 변화 시켰다는데 있다. 

아이폰 이전을 우리가 생각해 보자. 

인터넷을 하기 위해서는 우리는 집에 있는 PC 앞으로 가야 하거나, 사무실 내 자리 컴퓨터 앞 또는 PC 방으로 옮겨야 했다. 
즉, 장소의 제약이 생겼고, 이는 시간의 제약으로 이어졌다. 

하지만 아이폰 덕분에 이제는 언제 어디서든 내가 원하면 인터넷을 이용한다. 
외부에서 이동 중에도, 해외 여행 중에 유명한 관광지에서 정보를 검색하거나 인터넷뱅킹으로 이체를 할 수 있다. 

장소와 시간의 벽이 과감히 허물어졌다. 
당연히 인터넷 사용량이 늘어나게 되었다. 

하지만 내가 생각하는 가장 큰 변화는 인터넷 사용량의 증가가 아닌 인터넷 사용자의 층을 허문 것이라 생각한다. 

잘 생각해보면 과거 인터넷은 젊은이들의 소유물이라 불릴 정도로 어린아이들이나 노년층은 인터넷 사용을 어려워 했다. 정보를 검색하기 힘들었고 인터넷 뱅킹의 편리함을 즐길 수도 없었다. 

인터넷 사용자 층의 확대는 애플리케이션 개발/운영 환경에 크게 작용하게 된다. 
사용층이 늘어나다 보니 모 서비스에 대한 요구 사항이 증가하고, 빠르게 변화한다. 
애플리케이션으로 이윤을 추구하는 기업은 사용자 요구를 빠르게 반영하여 보다 편리하게 서비스를 만들어야만 경쟁력을 갖게 된다. 

" 인터넷 사용층의 확대가 많은 요구사항을 만들었으며 이에 따라 애플리케이션의 개발 및 운영 환경에 큰 변화가 만들어지게 되었다. 이것이 API 가 주목 받기 시작한 이유이다. "



개발 환경의 변화


개발 환경은 Monolithic 방식에서 MSA (Micro Service Architecture) 형태로 변화 할 수 밖에 없다. Monolithic 는 여러 기능을 하나의 덩어리로 개발해서 운영하는 환경을 말한다. 
관리 포인트가 많지 않아 운영 측면의 이점이 있다지만 어떤 변화에 발빠르게 따라가기엔 구조적으로 불리할 수 밖에 없다. 
어떤 기능을 변경해야 한다고 하면 여러 기능들이 복잡하게 얽혀 있기에 수정이 단순하지 않다. 수정되었다고 해도 검증을 해야 하는데 이 또한 쉽지 않다. 

바로 이런 단점들을 보완한 것이 MSA 방식이라 할 수 있다. 
Monolithic 안에 있는 여러 기능들을 서비스 단위로 각각 분리한 후 서비스 간 API 로 연동 시킨다. 이렇게 되면 각 서비스 별로 독립적이다 보니 기능의 수정도 검증도 배포도 Monolithic방식에 비해 상대적으로 아주 빠르다. 

요즘 애플리케이션 개발 운영 환경은 거의 MSA 형태로 진행된다. 
MSA 형태의 증가는 곧 API 사용량의 증가가 되는 것이다.

운영 환경의 변화 



운영 환경은 어떤가? 
예전은 On-premise 방식으로 데이터센터 내에 하나의 서비스 망을 구축하고 애플리케이션이 운영되는 서버도 갖추어 놓는다. 
사용량의 증가로 서버의 증설이 요구되면 서버를 추가로 구매해야 하고 네트워크에 연결하여 서비스가 잘되는지 살펴야 한다. 구매부터 서비스 투입까지 지켜야 할 절차 들이 있기에 시간적 소요가 많을 수 밖에 없다. 
그래서 변화하는 환경에 유연하게 대처할 수 있는 클라우드 환경이 인기가 높아진 것이다. 트래픽이 늘어나면 자동으로 서버를 추가하고 사용량이 줄면 다시 운영 서버의 수를 줄인다. 필요한 만큼 사용하고, 사용한 만큼만 비용을 지불하면 된다. 
서버의 증설과 감소를 자동으로 할 수 있게 해주는 것.. 바로 여기에도 API 가 이용된다. 

이처럼 시대적 요구에 따른 개발과 운영 환경의 변화가 API 의 사용량을 크게 증가 시켰다. 

현재 API 는 공공데이터포털, 웹사이트의 간편로그인등 다양한 곳에서 많이 사용되고 있으며, 현재 애플리케이션 운영의 핵심이라 볼 수 있다. 

서비스간 정보를 교환하는 중요한 기술인 API 는 2022년 1월 시행된 마이데이터 서비스에도 핵심적으로 이용되고 있다. 

요즘 애플리케이션 운영에 없어서는 안될 중요한 기술인 API.

우리가 API 보안을 신경 써야 하는 이유이다. 



2022년 11월 24일 목요일

Jmeter 사용법 #1 (설치, 실행)

경우에 따라서 웹 애플리케이션에 부하를 줘야 할 일이 생긴다. 

나는 AWS 의 auto scaling 을 학습하기 위해서이다. 

스케일링은 현재 운영되고 있는 시스템의 부하(Load) 여부에 따라 정해 놓은 기준을 벗어나는 경우 동작한다. 

그래서 인위적으로 부하를 줄 도구가 필요했다.

여러 가지 도구가 있겠지만, 실제 업무에 Jmeter 라는 도구가 꽤 사용되고 있어 사용법을 정리한다. 


Jmeter 는 Apache 에서 배포한 웹 스트레스 툴(Tool)이다. 

사용법이 크게 어렵지 않지만, 신이 인간에게 준 큰 선물인 망각이 있기에 정리해 놓을 필요가 있다. 


# 설치

설치 방법은 너무 간단하다. 

먼저 구글에서 jmeter 로 검색을 하면 아래와 같이 Jmeter 홈페이지가 나오는데 그리 바로 들어가면 된다. 


홈페이지에 접속하면 좌측에 Download 메뉴가 있으며 클릭하여 들어가면 쉽게 다운로드 링크를 찾을 수 있다. 


윈도우에서 사용할 거니까 윈도우 사용자 기준으로 아래 파일을 다운로드 한다. 




# 실행

다운로드 후 파일을 압축 해제 하면 아래와 같이 여러 폴더와 파일이 보인다. 

bin 폴더로 들어가 jmeter.bat 파일을 더블 클릭하여 실행한다.



다운로드 후 파일을 압축 해제 하면 아래와 같이 여러 폴더와 파일이 보인다. 

bin 폴더로 들어가 jmeter.bat 파일을 더블 클릭하여 실행한다.



2021년 8월 19일 목요일

[HTTP]HTTP/2 소개 - HTTP/2 의 주요 특징

이번 포스팅에서는 HTTP/2 에 대해 정리해 본다. 

HTTP/2 는 기본적으로 속도 향상을 위한 노력이 전부라고 봐도 과언이 아니다. 

HTTP/1.1 에서 응답 속도 측면에서 극복하기 힘든 제약 사항들에 대해 HTTP/2에서 많은 개선이 있었다. 

크게 5가지 정도가 있으며 이에 대해 상세히 알아 보도록 하자. 


#1. 멀티플렉싱 (Multiplexing)

HTTP/1.1 은 Persistent 와 Pipelining 기능을 통해 하나의 TCP 세션에 여러개의 요청을 보낼 수 있다. 

하지만, 요청은 반드시 순차적으로 서버에서 처리되어 브라우저로 전달되어야 한다. 그렇지 못하면 웹페이지 접속의 지연이 발생되며 이를 HOLB (Head of Line Blocking) 이라고 한다. 

순차적 요청 처리와 HOLB를 다소 낮추기 위해 도메인 샤딩(Domain Sharding) 이란 기술을 사용한다고 앞선 글에서 소개한 바 있다. 

하지만 도메인 샤딩 기술도 서버의 커넥션 부하를 고려하면 막연히 늘릴 수 있는 것이 아니기에 완벽한 해결 방법은 되지 못한다. 

HTTP/2 의 멀티플렉싱은 이런한 HTTP/1.1 의 부족한 부분을 완벽히 해소한다. 

멀티플렉싱은 하나의 TCP 커넥션만으로 해당 웹페이지의 모든 요청과 응답 데이터를 전송하며, 바이너리 프레임의 스트림 전송 방식을 통해 응답 순서에 무관하게 데이터를 처리한다. 

아래 그림을 보면 멀티플렉싱에 대한 이해가 쉬울 것이라 생각된다. 

HTTP/1.1 의 PIPELINING 과 멀티플렉싱의 가장 큰 차이는 순차적 응답 처리에 따른 HOLB 를 완벽하게 해결했다는 것이다. 




#2. 헤더 압축 (Header Compression)

HTTP/1.1 은 요청과 응답에 헤더(Header) 를 이용해서 여러 기능을 지원한다. 

예컨대, Host 헤더를 이용해서 가상 호스팅(Virtual Hosting) 을 가능하게 하고, Referer 헤더를 통해 어느 경로를 통해 사이트에 접근했는지를 확인할 수 있고, User-Agent 헤더를 이용해서 사용자 환경을 조사할 수도 있다. 

HTTP 헤더는 이처럼 다방면에서 활용할 수 있는 좋은 구성 요소이지만 요청/응답마다 같은 정보를 반복해서 전달해야 하는 비효율적인 측면도 존재한다. 

이는 대역폭(Bandwidth)를 점유를 높여 Throughput 을 높여 회선 비용을 증가시키고, 패킷  사이즈 증가는 PPS (Packets Per Second)를 높여 네트워크 장비의 처리 부담을 높힌다. 

이러한 내용들은 모두 HTTP 응답 시간(Latency) 에 관련된 것들이기에 개선이 필요하다. 

HTTP/2 에서는 중복되는 헤더의 반복 전송을 효율적으로 낮추기 위해 압축(Compression) 을 이용한다. 

압축은 허프만 코드를 이용하는 HPACK 알고리즘을 이용하며, 중복 내용의 반복 비율이 높을 수록 압축 효율은 커지게 된다. 

다음은 허프만 코드의 예를 다룬 그림이다. 

[ 출처 : https://playground10.tistory.com/98 ]

중복 횟수가 가장 많은 a 는 0
그 다음으로 많은 b와 r 은 100, 101
마지막으로 중복 횟수가 가장 적은 c와 d는 110, 111 이다. 

이처럼 중복 횟수가 많은 a 의 경우는 0 으로 가장 적은 비트를 이용하여 표현이 가능하게 된다. ( 압축 효율 높음 )

위 예제의 허프만 코드 계산 방법은 출처(https://playground10.tistory.com/98) 에 자세히 나와 있으므로 궁금하신 분들은 참고하면 좋겠다. 


#3. 서버 푸쉬 (Server Push)

HTTP 는 클라이언트의 요청으로 부터 시작되며, 요청한 컨텐츠에 대해서만 응답으로 전송하는 것이 일반적이다. 

하나의 HTML 웹페이지를 구성하는데 다양한 컨텐츠가 존재한다. 이를 테면 JS, CSS, JPG 등과 같은 여러 컨텐츠들이 하나의 HTML 페이지의 구성 요소라고 할 수 있다. 

따라서 웹페이지 하나를 브라우징 하기 위해서는 클라이언트는 HTML, CSS, JS, JPG 등 구성에 관련된 모든 컨텐츠를 요청해야 했다. 

HTTP/2 에서는 서버 푸쉬 기능을 통해 클라이언트가 요청하지 않은 데이터에 대해서 서버가 스스로 전송해 줄 수 있다. 

예를 들어 아래와 같이 main.html 을 구성하는 요소에 style.css, script.js, image.jpg 가 있다고 가정하자. 


클라이언트가 main.html 을 요청하면 HTTP/1.1 은 main.html 의 응답을 받고 main.html 안에 링크되어 있는 style.css, script.js, image.jpg 를 추가로 요청한다. 

요청한 모든 컨텐츠가 전송되면 main.html 의 페이지를 브라우저에서 보여주게 된다. 

HTTP/2 에서는 main.html 을 요청하면 서버는 main.html 의 구성 요소가 style.css, script.js, image.jpg 라고 정의된 경우 main.html 의 응답을 전송할 때 이 3개의 컨텐츠를 같이 전송한다. 

이렇게 되면 HTTP 트랜잭션은 기존 4개에서 1개로 줄기 때문에 RTT 가 감소하여 응답속도를 개선한다. 



#4. 우선 순위 (Stream Prioritization)

HTTP/1.1 에서는 웹페이지 렌더링에 대해 효과적으로 할 수 있는 옵션이 없었다. 

예를 들면, css 와 jpg 가 전달되는 과정에서 css 가 느리게 전달되는 경우 페이지 렌더링에 지연이 발생된다. 

따라서 페이지의 스타일을 정의한 css 가 먼저 처리될 수 있도록 우선순위를 HTTP/2에서는 정의할 수 있는데 이 기능을 Stream Prioritization 이라고 한다. 

아래 그림과 같이 페이지를 구성하는 요소가 html, css, jpg, js 가 있다고 가정하면 이에 대한 우선순위를 부여하여 먼저 전송처리 될 수 있도록 하는 기능이다. 



#5. 보안 통신 (HTTPS)

HTTP/2 는 평문 통신과 보안(TLS) 통신을 모두 지원하고 있고 이를 표현하는 방법은 다음과 같이 구분하고 있다.

- h2 : HTTP/2 + TLS

- h2c : HTTP/2

하지만 구글이나 네이버등 유명 홈페이지에 접속해 보면 HTTP/2 가 기본적으로 적용된 것을 볼 수 있으며, 보안 접속을 기본으로 하고 있음을 알 수 있다. 

따라서 HTTP/2 는 보안 접속을 기본으로 한다고 이해하는 것이 좋다.



이처럼 HTTP/2 는 HTTP/1.1 프로토콜에서 극복하기 어려운 처리 속도 지연 (latency) 에 대한 구조적 문제를 크게 해결하였다. 

그러면서도 동시에 HTTPS 의 보안 통신 채널을 통해 안전한 데이터 전송을 보장한다. 


흔히 보안과 처리 속도는 반비례 관계에 있다고 알고 있을 것이다. 

보안 수준을 높히면 속도가 느려지고 반대로 속도를 개선하려면 보안 수준을 낮추어야 했다.

HTTP/2 는 보안과 속도 라는 어찌보면 2마리의 토끼를 한번에 잡은 훌륭한 프로토콜인 셈이다. 


마지막으로 HTTP/1.1 과 HTTP/2 의 응답 속도 차이를 담은 테스트 영상을 통해 보안 통신을 하면서도 속도 개선이 얼마나 빨라졌는지 체감해 보도록 하자.  

CASE I

- 사용자와 웹서버간 RTT : 1ms

- 이미지 개수 : 900개 ( 하나의 이미지를 900개로 나눔 )


CASE II

- 사용자와 웹서버간 RTT : 500ms

- 이미지 개수 : 900개 ( 하나의 이미지를 900개로 나눔 )










2021년 7월 23일 금요일

[HTTP]HTTP/2 소개 - HTTP/1.1 제약 사항 (HTTP/2 등장 배경)

HTTP/2 가 출현하게 된 배경에 대해서 정리해 보기로 한다. 

HTTP/1.1은 1997년부터 2015년까지 오랜 시간 동안 많은 사랑을 받아온 프로토콜이다. 

하지만 복잡해지고 다양해지는 최근 웹어플리케이션들의 응답 속도를 개선하기에는 부족한 점이 몇가지가 있고, 이를 프로토콜 자체적으로 개선하기 힘들어 지게 된다. 


#1. PIPELINING 제약 사항

PIPELINING 은 여러개의 요청을 응답 여부에 상관없이 서버로 전달할 수 있는 기능이다. 
(PIPELINING 에 대한 자세한 설명은 여기 를 클릭하여 확인할 수 있다.)
RTT 감소 할 수 있는 획기적인 기술이지만, 아래와 같이 2가지 측면에서 실제 환경에 적용하기 어렵다. 

실제 환경 구현의 복잡성

PIPELINING 이 잘 동작하려면, 클라이언의 요청 순으로 서버의 응답이 처리되어야 한다. 
HTTP는 stateless 프로토콜이기 때문에 서버가 요청 순으로 응답을 처리해서 돌려주지 않으면 클라이언트에서는 이를 각 요청에 대한 올바른 응답으로 매칭 하기가 어렵다. 
즉, 아래와 같이 PIPELINING 요청이 있을 때, 요청 순대로 응답이 전달되어야만 한다는 이야기 이다. 

만약, 서버의 처리 지연 등과 같은 알 수 없는 문제로, 또는 중간 네트워크 장비의 라우팅 홉의 변경 등과 같은 네트워크적 요소로 인해 응답 순서가 바뀔 경우에는 이를 클라이언트는 올바르게 교정할 수 있는 방법이 존재하지 않는다.

PIPELINING 은 순서 바뀜(out-of-order)이 없는 어찌 보면 이상적인 환경에서나 쓸 수 있는 기능이 아닌가 싶다. 

추가적으로 이상적인 환경이라 할지라도 웹애플리케이션 접속 경로 상 존재할 수 있는 프록시 제품들도 PIPELINING 기능을 모두 지원해야 한다. 중간 프록시 장비가 PIPELINING 을 지원하지 않는다면 클라이언트가 전달한 다중 요청이 서버로 전달되지 못하기 때문이다. 
이렇게 되면 궁극적으로는 PIPELINING에 의한 RTT 감소 효과를 기대하기 어렵다. 

성능 이슈

클라이언트와 서버 모두 PIPELINING을 잘 지원한다고 하더라도 HOLB (head of line blocking) 때문에 응답 속도에 지연이 발생될 수 있다. 

HTTP는 stateless 프로토콜이어서 요청 순서대로 처리가 진행되어야 한다. 
어떤 이유로 인해 선행 요청의 처리가 지연되면 후행 응답이 먼저 전달된다고 하더라도 선행 요청의 처리가 완료 될 때까지 처리되지 못하고 대기해야 한다. 

(HOLB 에 대해서는 여기 를 클릭하면 상세한 내용을 확인할 수 있다. )

위에서 설명한 이유들로 인해 아래와 같이 대부분의 브라우저들이 PIPELINING 기능을 지원하지 않거나, 지원한다고 해도 기본적으로 비활성화(disable) 되어 있다.


[출처 : https://en.wikipedia.org/wiki/HTTP_pipelining]


#2. Domain Sharding 제약 사항

PIPELINING 의 현실적 적용의 어려움으로 인해 나온 대안이 바로 Domain Sharding 이다. 

Domain Sharding 은 아래 그림으로 이해하면 쉽다. 



Without Domain Sharding

모든 컨텐츠를 단일 도메인에서 서비스하는 경우이다. 

  • 웹서비스 도메인 : www.example.com 
  • css,js,img 제공 도메인 : www.example.com
With Domain Sharding

www.example.com 의 홈페이지에 사용되는 컨텐츠 별로 아래와 같이 구분한다.
  • 웹서비스 도메인 : www.example.com
  • css 제공 도메인 : css.example.com
  • js 제공 도메인 : js.example.com
  • img 제공 도메인 : img.example.com

HTTP 는 선행 요청이 잘 전달되어야만 후행 요청이 정상적으로 처리된다. 때문에 위와 같이 3개의 컨텐츠(style.css, script.js, img.jpg)를 전달 받기 위해서는 단일 TCP 커넥션으로는 RTT(round trip time) 가 요청 갯수 만큼 늘어나게 된다. 

하나의 웹서비스 도메인을 컨텐츠별로 위와 같이 나눈다면 도메인별로 TCP 세션이 각기 맺어지게 되므로 RTT를 획기적으로 줄일 수 있다. 

Domain Sharding 의 이런 장점을 기반으로 도메인을 많이 나누게 되면 어떻게 될까?
막연히 좋기만 할까? 답은 "그렇지 않다" 이다. 
도메인은 DNS Lookup 과 연관이 된다. 도메인이 많으면 DNS Lookup 을 많이 수행해야 하고 사용되는 도메인들의 커넥션 또한 서비스를 위해 안정적으로 유지하여야 한다. 

야후에서 연구한 바에 따르면 하나의 서비스에 대해 2~4개 정도의 도메인을 운영하는 것이 적당하고, 그 이상이 될 경우에는 성능에 저하를 초래하게 된다고 한다. 

[ 출처 : https://blog.stackpath.com/glossary-domain-sharding/ ]


#3. 프로토콜 자체의 오버헤드

클라이언트와 서버간 통신할 때 HTTP 헤더와 쿠키 정보가 포함된다. 

HTTP 헤더와 쿠키는 웹(WEB)을 발전시키는데 큰 역할을 한 요소임에 틀림없으나 요청/응답마다 동일한 헤더 정보가 반복되어 포함되는 것은 큰 고민거리였다. 

아래는 네이트 홈페이지 접속 시 전달되는 2개의 요청 헤더이다. 


붉은색으로 표시한 부분들이 동일한 내용의 HTTP 요청 헤더 내용이다. 
위에서는 요청에 대한 내용만 정리했으나 응답도 마찬가지이다.

이러한 동일한 내용이 반복되는 헤더와 쿠키 정보는 별도의 압축이나 인코딩 과정이 없기 때문에 전달되는 패킷의 사이즈를 키운다. 
패킷의 사이즈가 커지면 네트워크 대역폭(bandwidth)를 키우게 되고, 이는 pps (packets per second) 를 높여 네트워크 장비의 부담을 높힌다. 
이는 결국 latency 증가로 이어질 수 밖에 없다. 

크게 위 3가지 내용들이 긴 시간 사랑을 받아온 HTTP/1.1을 물러나게 하고 HTTP/2 를 등장 시킨 배경이라 할 수 있다. 

끝~

2021년 6월 29일 화요일

[HTTP]HTTP/2 소개 - HTTP 프로토콜 역사

HTTP(Hyper Text Transfer Protocol)는 우리가 아는 현재의 인터넷 환경을 만들었다 라고 해도 전혀 부족함이 없을 것이다. 

아니 HTTP가 있었기에 현재의 인터넷 환경이 탄생하고 발전하게 되었다고 하는 게 맞을 것이다.

애플리케이션 프로토콜인 HTTP는 1989년 WWW(World Wide Web)의 창시자 팀버너에 의해 제안 되었다.

인터넷 발전에 대한 요구가 증가하면서, HTTP는 최상의 성능을 제공하기 위해 지속적으로 발전해야만 했다.

초창기 HTTP는 수 많은 개편 과정을 거쳤으며, 1997년에 HTTP/1.1이 첫 번째 표준이 되었다.

1997년 HTTP/1.1은 표준으로 선정되면서 HTTP/2가 등장하기까지 무려 18년동안 꾸준히 사용되어 왔다. 

현재 웹을 이용하는 많은 사용자들은 좀 더 화려하고, 멋진 홈페이지 서비스를 기대한다. 웹이 이미 생활의 대부분을 차지하게 된 요즘 이러한 사용자의 요구는 시간이 흐를수록 증가할 것이라는 건 너무도 자명한 일이다. 

HTTP/1.1은 이러한 시대적 요구를 수용하기에는 현재 너무 버거운 상태이다. 

18년 동안의 큰 사랑을 받아온 HTTP/1.1 이 HTTP/2에게 바톤을 넘겨야 할 시점이 온 것이다.

여기서는 HTTP/1.1 의 제약사항이 무엇이며 이를 극복하기 위해  HTTP/2 가 어떻게 바뀌었는지? 앞으로 HTTP/2가 풀어야 할 숙제는 무엇인지 등을 살펴보기로 한다.


# 1991年 - HTTP/0.9

HTTP 의 첫 번째 프로토콜인 HTTP/0.9 는 단일 라인(One-line) 프로토콜로 불렸다.

사실 HTTP 초기 버전에는 버전 넘버가 부여되지 않았다. HTTP/1.0 이후 초기 버전을 구분하기 위해 0.9로 표시하고 있다.

단일 라인 프로토콜인 HTTP/0.9 는 다음과 같은 특징이 있다. 

  • 요청만으로 구성되며 요청 Method 는 오직 GET 만 지원
  • 요청은 오직 단일 라인으로 되어 있으며, Method 다음에 요청 URL이 따른다. 
  • 응답은 엄청 심플하며, 응답 바디로만 구성됨
  • 오로지 HTML 문서만 전송 가능
  • HTTP 헤더 및 상태/에러 코드는 존재 하지 않음.
HTTP/0.9의 요청과 응답을 패킷에서 확인하면 다음과 같다.


요청은 GET /main.html 로 매우 간단하고, 응답은 어떤 정보 없이 html 내용만 그대로 전송된다. 

지금의 인터넷 환경을 기준으로 HTTP/0.9를 바라보면 매우 초라해 보이지만, WWW를 탄생 시켰다는 점에서 보면 가장 훌륭한 프로토콜로 평가할 수도 있겠다.

무(無)에서 유(有)를 창조하기가 정말 어려운 것처럼...



# 1996年 - HTTP/1.0


HTTP/0.9 는 단순 HTML 문서만 열람하기 위한 프로토콜이어서, 이에 대한 지원 범위를 확장할 필요성이 생겼다. 

초기 HTTP 프로토콜의 지원 범위를 확장하고, 실제 인터넷 서비스를 가능케 하기 위해 다음과 같이 몇가지의 주요 내용이 변경된다.


  • 요청과 응답에 필요한 정보를 담은 HTTP 헤더를 추가함
  • 다중 헤더 정보를 식별하기 위해 헤더와 헤더 사이는 줄바꿈(CRLF)으로 구분함.
  • 버전 정보가 요청과 응답에 포함됨.
  • 응답에 상태/에러 코드를 추가함.
  • Content-Type의 헤더를 통해 HTML 외 다양한 컨텐츠를 지원하게 됨.


HTTP/1.0 의 요청과 응답은 다음과 같다.


HTTP/0.9와는 달리 요청과 응답에 버젼정보와 헤더 내용이 포함됨을 볼 수 있다. 


HTTP/1.0 의 내용이 결정되기 까지 여러 논의가 진행되었으나, 뭔가 과정이 체계적이진 못했다고 한다. 

논의 주체들간의 이견들이 분명 있었을테고 이를 조율해 가는 과정이 순탄치 않았던 것으로 보인다. 

이런 문제점을 해소하기 위해 "HTTP 워킹 그룹"이 만들어졌고, RFC 1945 가 잘 정리되면서 1996년 5월 HTTP/1.0 이 릴리즈 되었다. 

다만, HTTP/1.0 (RFC 1945) 은 논의되었던 내용들의 정보를 제공하는 목적의 문서이며, 그래서 공식적으로 HTTP 인터넷 표준(Internet Standard)은 아니었다. 

표준 재정 여부와 무관하게 HTTP/1.0 의 등장으로 이때부터 브라우저를 통한 웹이 본격적으로 시작되었다고 할 수 있다. 


# 1997年 - HTTP/1.1


HTTP/1.0 이 발표되고 불가 1년이 지나지 않았는데, HTTP/1.1(RFC 2068) 이 공식적으로 릴리즈 되었고, 이것이 HTTP 의 공식적인 첫 번째 인터넷 표준이다. 

HTTP/1.0 의 발표가 1996년 5월 이었고, HTTP/1.1 이 1997년 1월이니 HTTP/1.0의 수명은 7개월이었던 셈이다. 

좀 더 정확히 이야기 하면 HTTP/1.1은 1997년 1월 발표 후 성능적 향상을 많이 개선하면서 1999년 1월 RFC 2616 으로 업그레이드 되었다. 

우리가 현재 사용중인 HTTP/1.1은 RFC 2616 에 기본을 두고 있다고 하겠다. 

그렇다면 왜 HTTP/1.0 발표 후 HTTP/1.1 을 급하게 추진하였을까? 

HTTP/1.0 의 제약 사항이 많이 복잡화 되고, 다양한 컨텐츠 기반의 웹서비스를 제공하기에 좀 부족한 부분이 있기 때문이다. 

그 내용은 아래와 같다. 


  • 하나의 TCP 커넥션 당 1개의 컨텐츠만 요청이 가능
  • 하나의 IP 에 여러 도메인 서비스가 불가능


위 2가지 사항이 핵심적인 내용인데 이 중에서 TCP 커넥션 당 1개의 컨텐츠만 요청할 수 있는것이 가장 큰것으로 보인다. 

이 이야기는 하나의 페이지에 20개의 컨텐츠가 있다면 브라우저는 이를 화면에 보여주기 위해 20개의 TCP 커넥션을 필요하다는 이야기가 된다. 

서버와 클라이언트에게 모두 부담이 되는 사항인것이다.


그리하여 릴리즈된 HTTP/1.1을 보면 아래 내용들을 지원하고 있다.


  • 세션 유지(Persist) 와 파이프라이닝(Pipelining)
  • Host 헤더 지원을 통한 Virtual Hosting 
  • 청크(Chunked) 전송, 압축과 해제, 캐싱 관련 directives 추가
  • 클라이언트 식별과 쿠키 등..


아래는 HTTP/1.1 의 요청과 응답이다. 

HTTP/1.0 과는 달리 연결 유지 (Persistence) 를 통해 하나의 TCP 세션에 2개의 컨텐츠를 요청하여 받은 경우이다. 


HTTP/1.1의 문제점


인터넷이 발전함에 따라 지금까지 웹사이트는 점점 커졌고 복잡해졌다. 

아래 그래프는 2010년 11월 ~ 2021 5월까지의 페이지의 전체 사이즈 추이를 나타낸 것인데..

데스크톱 이용자를 위한 페이지는 4.5배 늘었고, 모바일 이용자를 위한 페이지는 13.4 배 커진것을 볼 수 있다. 



최근 홈페이지의 FCP (first contentful paint)는 데스크톱 이용자의 경우 2.2초, 모바일 이용자의 경우 5초가 소요되는 것으로 조사된다. 



FCP는 웹페이지의 접속 시 첫번째 컨텐츠가 뜨기까지 소요되는 시간을 의미한다. 

이용자들은 FCP 가 긴 경우 페이지 접속을 멈추고 다른 웹사이트로 방문할 가능성이 커진다고 한다. 

알려져 있기를 웹사이트에 사용자들이 오래 머물게 하려면 컨텐츠의 질도 중요하겠지만 FCP 가 1초 미만이 되어야 한다고 한다. 


FCP를 낮추기 위해서는 HTTP/1.1 로는 더 이상 힘들어졌다. 

HTTP/1.1 이 가지고 있는 아래 제약사항들 때문이다.


  • 프로토콜 자체의 부하
  • TCP 프로토콜의 한계 (slow start)
  • PIPELINING 의 비현실적 적용 환경 및 HOLB 문제점
  • 순차적인 요청/응답 환경


위 내용에 대해서는 다음 포스팅에서 상세히 다뤄보겠다. 


# 2015年 - HTTP/2


위 내용에서 다룬 HTTP/1.1 의 문제점을 획기적으로 개선한 프로토콜이 2015년에 등장했다. 

HTTP/2는 2009년 구글이 HTTP/1.1 의 문제점을 해결하고자 먼저 시작한 SPDY 를 모태로 한다. 


SPDY 는 다음 내용을 담고 있다. 


  • 페이지 로딩 타임 50% 감소
  • 구축 복잡성 최소화
  • 웹사이트 컨텐트 변경 불필요


2009년 구글에 따르면 SPDY를 통해 페이지 로딩 타임을 55% 개선하였다고 한다. 2012년 SPDY는 크롬, 파이어폭스, 오페라에서 공식적으로 최초 지원하기 시작했다. 

HTTP 워킹 그룹은 SPDY 를 근간으로 한 HTTP/2 를 명세화하기 시작했고 2015년에 공식적으로 RFC 7540으로 표준화 하였음을 릴리즈하였다. 


HTTP/2는 아래 대표적인 4가지 기능을 통해 HTTP/1.1에서 가지고 있는 제약 사항을 극복했다. 


  • Binary Frame & Multiplexing
  • Server Push
  • Header Compression
  • Stream Prioritization


다음 포스팅에서는 HTTP/2 의 등장 배경인 HTTP/1.1 의 제약 사항들에 대해 상세히 정리해본다.


끝~

2021년 2월 25일 목요일

[HTTP]HOL 블로킹 (Head of Line Blocking)

HTTP 통신에서 성능에 큰 영향을 주는 HOL(Head Of Line) Blocking 에 대해서 정리해 본다. 

웹의 보편화와 함께 HTTP 프로토콜은 성능 측면, 특히 지연속도(Latency) 를 줄이려는 노력을 끊임없이 하고 있다. 

HTTP 1.0 에서 HTTP 1.1 로 발전함에 따라 추가된 다음의 기능들이 크게 대표적이라 할 수 있겠다. 

  • Persistent
  • Pipelining
이 밖에도 HTTP 캐시(Cache) 에 대한 헤더들도 HTTP 1.1에 많이 추가되거나 발전되었는데, HTTP 캐시 역시 궁극적으로는 네트워크를 통한 컨텐츠 요청 수를 줄여 응답 속도를 개선하려는 것이 가장 큰 이유이다. 

이런 많은 노력에도 불구하고 웹 지연 속도의 핵심적인 원인인 HOL 블로킹은 HTTP 1.1 에서 해결하지 못했다.  아니, 어찌 보면 HTTP 1.1 에서 생긴 문제라고 할 수 있겠다. 

HTTP/2 가 되서야 Multiplexing 기능에 의해 HTTP 프로토콜단의 HOL Blocking은 해소가 되게 된다. 
HTTP/2 에 대해서는 다음 포스팅에 자세히 다루도록 하겠다. 

그럼 HTTP 통신에서 Latency 지연을 유발하는 HOL Blocking 에 대해 정리해 보자. 
HTTP 1.1 에서 Persistent + Pipelining 을 통해 다음과 같은 통신이 가능해졌다. 


Pipelining 을 통해 3개의 요청을 한번에 보내게 되면 왕복 시간(Round-Trip time)을 줄일 수 있어 응답 지연(Latency) 에 매우 좋은 효과를 기대 할 수 있다. 

하지만 만약 첫번째 요청의 처리가 서버에서 오래 걸릴 경우 두번째, 세번째의 응답이 같이 지연되게 된다. 이게 HOL Blocking 이다. 




예로 들면.. 

요리를 하는 누군가에게 다음 3가지를 동시에 주문한다고 하자. 
  • 1번 요청 : 삼계탕
  • 2번 요청 : 양파 1개
  • 3번 요청 : 당근 1개
요청을 받은 사람은 당근과 양파는 쉽게 내줄 수 있음에도 불구하고 첫번째로 들어온 주문인 삼계탕을 다 만들기 전까지 내 줄수 없게 되는데.. 이게 HOL Blocking 인 셈이다. 

그럼 다음과 같은 궁금증이 생기지 않는가? 

"왜 순서대로 응답을 줘야만 하지? 먼저 처리할 수 있는 것들은 먼저 응답을 주면 안되나?"

이에 대한 답은 RFC 문서를 참고하면 해소된다. 

웹 서버는 Pipelining 을 통해 한번에 여러 개의 요청을 받을 수 있으나, 응답 순서는 요청 순에 따라야 함이 HTTP 프로토콜의 규칙(Rule)인 셈이기 때문이다. 

RFC 2616의 8번째 섹션에서 다음의 내용을 다루고 있으니 참고하면 좋겠다. 

8.1.2.2 Pipelining

A client that supports persistent connections MAY "pipeline" its requests (i.e., send multiple requests without waiting for each response). A server MUST send its responses to those requests in the same order that the requests were received.

-> 서버는 반드시 응답을 요청 순서(request in the same order)에 맞추어 전달해야 한다.

Clients which assume persistent connections and pipeline immediately after connection establishment SHOULD be prepared to retry their connection if the first pipelined attempt fails. If a client does such a retry, it MUST NOT pipeline before it knows the connection is persistent. Clients MUST also be prepared to resend their requests if the server closes the connection before sending all of the corresponding responses.

Clients SHOULD NOT pipeline requests using non-idempotent methods or non-idempotent sequences of methods (see section 9.1.2). Otherwise, a premature termination of the transport connection could lead to indeterminate results. A client wishing to send a non-idempotent request SHOULD wait to send that request until it has received the response status for the previous request.


* RFC 2616 의 8번째 섹션 전문 : [여기] 를 클릭하여 확인

-끝-



2021년 2월 24일 수요일

[HTTP] HTTP 1.0 과 HTTP 1.1 의 큰 차이점

최근 HTTP 강좌라는 주제로 블로그에 포스팅 한 내용을 좀 살펴봤는데 HTTP 1.0 과 HTTP 1.1 의 차이에 대해 정리해 놓은 게 없음을 알았다. 

필자가 생각보다 현업에서 신입 또는 대리급의 경력직을 인터뷰할 때 즐겨 묻는 주제이기도 하고 HTTP/2 에 대해서 포스팅 하려고 준비 중에 있는데 내용을 이해하고 있는게 좋을 것 같기도 하고 해서 포스팅 해 본다.

과거 사회에 첫발을 내딛고 웹 캐시(Web Cache) 서버를 기술 지원 하는 엔지니어가 되어 가는 과정에서 수학의 정석처럼 읽어 보았던 자료에 의하면 HTTP 1.1 의 가장 큰 특징은 다음 3가지로 표현하고 있다. 

  1. 커넥션 유지 (Persistent Connection)
  2. 호스트 헤더 (Host Header)
  3. 강력한 인증 절차 (Improved Authentication Procedure)


위 3가지에 대해 정리해 보자. 

1. 커넥션 유지 (Persistent Connection)

HTTP 프로토콜은 클라이언트-서버 간 데이터를 주고 받는 응용 계층의 프로토콜이다. 
HTTP 를 이용한 데이터 전달은 TCP 세션 기반에서 이루어 진다. 

HTTP 1.0 과 1.1 의 차이는 TCP 세션을 지속적으로 유지할 수 있느냐? 없느냐에 차이를 둔다. 
아래 그림을 참고하면 이해가 쉽다. 




위 그림과 같이 HTTP 1.0 은 요청 컨텐츠마다 TCP 세션을 맺어야 한다. 
(1 GET / 1 Connection)
이와 다르게 HTTP 1.1 은 Persistent 기능을 이용하여 한개의 TCP 세션을 통해 여러개의 컨텐츠 요청이 가능하다. 
(N GET / 1 Connection)

이 차이점으로 통해 서버는 TCP 세션 처리 부하를 줄일수 있기에 좋고, 그만큼 클라이언트는 응답속도가 개선되어 좋다. 

1-1. 파이프라이닝 (Pipelining)

Persistent 기능을 통한 커넥션 유지와 함께 HTTP 1.1 에서 지원되는 기능이 하나 더 있다. 
바로 "파이프라이닝(Pipelining)" 이다. 

해당 기능은 먼저 아래 그림을 보면 이해가 쉽다. 


HTTP 요청은 순차적으로 이루어진다. 
위 그림(왼쪽)과 같이 3개의 컨텐츠를 요청한다고 가정하면 파이프라이닝 기능이 없는 경우.. 
요청#1 -> 응답#1 -> 요청#2 -> 응답#2 -> 요청#3 -> 응답#3 
과 같이 진행된다. 

즉, 요청#1에 대한 응답#1을 정상적으로 받아야만 다음 요청#2가 진행되고, 마찬가지로 응답#2를 받아야 요청#3이 진행된다. 

어떠한 이유로 응답#1이 없는 경우라면 요청#2, 요청#3은 진행되지 못하게 되어 문제가 된다. 
설사 문제가 없더라도 상식적으로 비효율 적이란 것을 느낄 수 있을 것이다. 

파이프라이닝은 이를 개선한 기능이다. 
위 그림(오른쪽)과 같이 동시에 요청#1,요청#2,요청#3을 보내고 이에 대한 각각의 응답을 받아 처리한다. 

이는 응답 속도를 높혀 페이지 뷰의 속도를 빠르게 할 수 있는 기능이다. 



2. 호스트 헤더 (Host Header)

버츄얼 호스팅이라고 들어봤으리라 생각한다. 
HTTP 1.1로의 발전이 없었다면 불가능한 서비스이다. 
HTTP 1.0 환경에서는 하나의 IP에 여러 개의 도메인을 운영할 수 없다. 
도메인 마다 IP를 구분해서 준비해야 한다. 도메인만큼 서버의 개수도 늘어날 수 밖에 없는 구조이다. 

HTTP 1.1 에서 Host 헤더의 추가를 통해 비로소 버츄얼 호스팅이 가능해졌다. 
버츄얼 호스팅은 아래 그림과 같으니 참고하면 좋겠다. 



3. 강력한 인증 절차 (Improved Authentication Procedure)

HTTP 1.1 에서 다음 2개의 헤더가 추가되었다. 
  • proxy-authentication
  • proxy-authorization
실제 서버에서 클라이언트 인증을 요구하는 www-authentication 헤더는 HTTP 1.0 에서부터 지원 되어 왔으나, 클라이언트와 서버 사이에 프록시가 위치하는 경우 프록시가 사용자의 인증을 요구할 수 있는 방법이 없었다. 

위 헤더에 대한 상세 내용은 기존 강좌를 참고하면 좋겠다. 

인증 관련 헤더 내용 : [여기]를 클릭하세요


-끝-

2018년 1월 29일 월요일

HTTPS에서 SSL 세션 아이디(Session ID) 와 세션 티켓(Session Ticket) 차이

웹 통신에서 HTTPS 트래픽을 처리하기 위해 클라이언트와 서버간 SSL 세션을 맺는 HTTPS 핸드쉐이크 과정 다들 아시지요?

! 아래 그림을 참고해 보겠습니다.

.. 일반적인 HTTPS 핸드쉐이크 과정입니다. 위 과정이 모두 완료되어야 클라이언트-서버간 암호화된 데이터를 주고 받을 수 있습니다.

그런데 여러분..
데이터를 보내려고 할때마다 위와 같이 인증서를 확인하고.. 암호화 방식을 결정하며.. 데이터 암호화에 사용할 키를 생성하고 서로 교환하는 과정을 반복한다면.. 얼마나 비효율적일까요?

클라이언트와 서버간 Latency 50ms 라고 한다면.. 실제 데이터를 교환하기 위해 매번 200 ms(클라이언트 기준) 의 핸드쉐이크 과정이 포함되어야 합니다.
가뜩이나 암/복호화로 인해 서버의 응답 지연시간이 HTTP 보다 느려지는데.. 핸드쉐이크 과정까지 매번 수행하게 되면.. 속도측면에서 얼마나 만족스러운 결과를 기대할 수 있을까요?

그렇습니다. 우리가 지금 고민하고 있듯이.. SSL 프로토콜을 만드신 분들께서도 이런 사항을 고민하셨겠지요~..
HTTPS 핸드쉐이크의 과정을 대폭 개선한 간소화된 핸드쉐이크 과정이 이미 나와있습니다.
크게 보면.. 2가지네요~.. 

그 중 먼저 첫 번째두둥~

1.     SSL Identifier 메커니즘

일단, 최초로 서버와의 통신을 시도하는 클라이언트는 어쩔 수 없습니다.
Full 핸드쉐이크 과정을 처음엔 거쳐야 합니다.

먼저 클라이언트는 최초 접속이기 때문에 Client Hello 메시지에 session id 값이 없습니다.
아래 2번과정에서 서버는 Server Hello 메시지에 Session Identifier 를 포함하여 전달합니다



클라이언트는 서버에서 발행해 준 Session Identifier 정보를 로컬에 저장하게 되는데요~..
클라이언트는 다음 HTTPS 세션을 맺을 때 이 값을 사용하게 됩니다
저장해 둔 Session Identifier 값을 Client Hello 메시지에 포함하여 전달합니다

서버는 클라이언트가 보내준 Session Identifier 정보를 확인하고, 이를 다시 사용해도 된다고 판단이 되면, Server Hello 메시지에 같은 Session IDs 값을 포함하여 전달합니다. (2번 과정)

이러면.. 다음 과정들이 생략됩니다.

ㄱ.   서버 인증서 확인
ㄴ.   암복호화에 사용할 Cipher Sutes 결정
ㄷ.   암복호화에 사용할 암호화 키 교환

이전에 사용했던 Cipher Suite 와 암호화 키를 다시 재활용하게 되므로 Full 핸드쉐이크 과정보다 2 Step 정도가 간소화 되네요~.. 
처음과 같이 하나의 과정의 Latency 를 50ms 로 가정한다면.. 100ms 정도를 개선하는 효과가 생깁니다.

클라이언트-서버간 주고 받아야 할 트랜잭션이 많을수록 효과는 크게 됩니다



2.     Session Ticket 메커니즘

두번째 방법은 Session Ticket 메커니즘입니다.

이 역시도 최초에는 Full 핸드쉐이크 과정을 수행해야 합니다. 가장 마지막 과정에서 서버는 “New Session Ticket”메시지를 클라이언트에게 전달합니다. 여기에는 암복호화에 사용할 마스터 키와 Cipher Sutes 알고리즘이 포함되어 있습니다.

세션 티켓의 정보는 서버만 알고 있는 키로 안전하게 암호화 하여 처리합니다.
세션 티켓 메커니즘은 TLS 확장 옵션입니다. 해당 메커니즘은 클라이언트와 서버가 모두 지원해야만 사용할 수 있습니다.

클라이언트는 Client Hello 메시지의 확장 옵션부분에 값이 없는 Session Ticket 을 같이 포함하여 전달함으로써 Session Ticket 메커니즘을 지원함을 알립니다. 서버 역시 Server Hello 메시지에 같은 방식으로 지원여부를 알립니다


클라이언트가 다시 서버에 HTTPS 통신을 시도하게 되면 다음과 같이 간소화된 절차를 거치게 됩니다.

클라이언트나 서버 둘 중 하나도 이를 지원하지 않는 경우에는 Session Identifier 메커니즘을 사용하게 됩니다.

Session Ticket 메커니즘이 상세히 기술된 RFC 5077 에는 Session Identifier 보다 Session Ticket 메카니즘의 사용을 더 권장하고 있습니다.

이유는 두가지인데요~

첫째, 서버의 메모리 사용이 적습니다. Session Identifier 는 서버가 발행한 Session IDs 값들을 모두 메모리에 기억하고 있어야 합니다
따라서 접속사용자가 많은 경우에는 서버 메모리 자원에 영향을 줄 수 있습니다
반면, Session Ticket 메커니즘은 클라이언트가 해당 내용을 기억하고 서버로 전달하는 방식이라 서버의 메모리 자원에 영향이 적습니다.

둘째, L4에 의한 부하분산 환경에서는 Session Identifier 메커니즘을 사용하는데 문제가 될 수 있습니다.
L4 의 부하분산 방식이 사용자의 IP를 참고하지 않는 방식의 경우 사용자를 동일한 서버로 분산하지 않기 때문에 SSL 세션 재활용 효율이 적습니다
이는 서버가 정보를 저장하고 이용하기 때문인데, 반면 클라이언트가 정보를 전달하는 방식인 Session Ticket을 사용할 경우에는 L4의 환경에 영향을 전혀 받지 않습니다

간만에 블로그 내용을 포스팅합니다. ^^
2018년은 새해 시작하면서 엄청 바쁘네요~.. 블로그 포스팅에도 앞으로 신경 쓰겠습니다. 

끝~~