개요
HTTP와 HTTPS는 인터넷을 사용한다면 항상 주소 맨 앞에 붙는 단어로 많이 보게됩니다. 그런데 한번도 정확히 정리해보지 않아서 개념을 찾아보고 정리하게 되었습니다.
HTTP (Hyper Text Transfer Protocool)
HTTP는 클라이언트와 서버가 데이터를 주고받기 위한 프로토콜입니다. OSI L7에 해당하며, 80번 포트를 사용합니다.
HTTP 특징
1. 비연결성 (Connectionless)
HTTP는 TCP 기반의 프로토콜로, 한번 요청과 응답이 완료되면 서버는 클라이언트와 연결을 끊습니다. 이는 서버 자원을 절약하고 더 많은 클라이언트를 받을 수 있다는 장점이 있지만, 매 연결마다 새로운 연결을 (Handsake) 만들어야 한다는 단점이 있습니다. 그래서 HTTP 1.1 버전에서는 Keep Alive 기능을 추가해서 일정 시간동안 연결이 유지할 수 있도록 개선하기도 했습니다.
버전별로 살짝식 다른데, 버전별 정리는 다른 글에서 자세히 정리해보겠습니다. 일단 여기에 작성되는 정보는 모두 1.1 기준입니다.
2. 무상태 (Stateless)
HTTP 통신은 이전에 전송된 요청이나 응답을 기억하지 않습니다. 이는 서버에 상태를 저장하지 않아서 확장성이 좋아진다는 장점이 있지만, 상태를 유지해야하는 작업(로그인 인증 정보 등)에서는 불리할 수 있습니다. 그래서 상태 저장이 필요하면 쿠키, 세션과 같은 방법을 사용합니다.
Stateless가 확장성이 좋은 이유
개인적으로 왜 Stateless가 확장성이 좋은지 이해가 잘 안되서 조금 더 정리해 봤습니다.
만약 서버가 응답을 항상 기억한다면, 기존 서버가 한계에 다다랐을때 새로운 서버를 즉각적으로 투입하기가 어렵습니다.
기존 서버의 상태를 모두 새로운 서버에도 동기화 해야 응답에 문제가 생기지 않겠죠.
그래서 상태를 저장해야 한다면 DB를 쓰거나, 쿠키, 세션을 활용하고, HTTP는 Stateless하게 동작하게 된겁니다.
HTTP 동작 과정
1. 3-Way Handsake
HTTP는 TCP 기반이므로 TCP 프로토콜의 Handsake 과정을 먼저 수행합니다.
-
Syn-Sent
클라이언트가 서버에 연결을 요청하는 SYN 패킷을 전송합니다. 이때 임의의 값(예시: seq(100))을 포함시켜 보냅니다. -
Syn-Reviced
SYN 패킷을 받은 서버는 요청을 수락하면 SYN+ACK 패킷을 보내서 응답합니다. 이때 임의의 값(예시: seq(200))과 전송받은 SYN 패킷의 값에 1을 더한 값(예시: ack(101))을 같이 포함시킵니다. -
Established
클라이언트는 서버로부터 받은 SYN+ACK 패킷을 잘 받았다는 의미로 SYN+ACK 패킷에 포함된 임의의 값에 1을 더해 포함시켜 (예시: seq(101) + ack(201)) ACK 패킷을 보냅니다. ACK 패킷을 수신한 서버도 연결이 수립되었음을 알고 서버와 클라이언트의 통신 준비 상태가 완료됩니다.
2. HTTP Data Transfer
HTTP 데이터를 주고받는 과정입니다. 클라이언트에서 요청하면 서버에서 응답을 주는 방식으로 진행됩니다.
3. Connection Close
HTTP는 비연결성 특징을 가지므로 한번 요청-응답이 끝나면 연결을 완전히 종료합니다.
HTTP 동작 과정을 보면 왜 1.1에서 Keep Alive 기능을 추가했는지 조금 더 명확히 보입니다. 매번 같은 클라이언트가 서버에 요청 할 때 마다 3-Way Handsake를 진행하는게 비효율 적이니까 같은 클라이언트가 일정 시간 내에 다시 요청한다면 TCP 연결을 살려두고, 데이터를 바로바로 주고받을 수 있게 만든게 Keep Alive입니다.
HTTP 메세지 구조
HTTP는 텍스트 기반으로, Start line, Header, Blank, Body로 나뉩니다.
Request Message
클라이언트가 서버에게 요청하는 메세지입니다.
1
2
3
4
5
GET /hello.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
(공백)
(Body 없음)
Start Line
- 메소드(Method, GET): GET, PUT, POST 등 이 요청이 어떤 동작의 요청인지 표기합니다.
- 경로(/hello.html): 접근할 위치를 표기합니다.
- 버전(HTTP/1.1): HTTP 버전 중 어떤 버전을 사용할지 표기합니다.
Header
- 요청에 대한 추가적인 정보입니다. Host, User-Agent 등 key-value 형태로 구성됩니다.
Blank
- 헤더와 바디를 구분하기 위한 공백입니다.
Body
- 전송할 데이터입니다.
Response Message
서버가 클라이언트의 요청에 응답하는 메시지입니다.
1
2
3
4
5
6
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2024 12:28:53 GMT
Content-Length: 120
Content-Type: text/html
(공백)
<html><body><h1>Hello!</h1></body></html>
Start Line
- 버전(HTTP/1.1): HTTP 버전 중 어떤 버전을 사용할지 표기합니다.
- 상태코드(Status Code, 200): 요청에 대한 결과 상태를 코드로 나타냅니다.
Header
- 응답에 대한 추가적인 정보입니다. 요청과 동일하게 key-value 형태로 구성됩니다.
Blank
- 헤더와 바디를 구분하기 위한 공백입니다.
Body
- 전송할 데이터입니다.
HTTP Method
HTTP 요청시 해당 요청이 어떤 동작을 의도하는지 표현하기 위해 사용합니다.
- GET: 데이터 조회
- POST: 데이터 생성
- PUT: 데이터 수정
- PATCH: 데이터 일부 수정
- DELETE: 데이터 삭제
이 외에도 HEAD, OPTION이 있습니다.
HTTP Status Cod
HTTP는 응답시 상태를 숫자 코드로 표현합니다.
- 1xx(정보): 요청을 받고 처리중인 상태를 표현
- 2xx(성공): 요청을 성공적으로 처리
- 3xx(리다이랙션): 요청을 완료하기 위한 추가 동작 필요 (주소 이동)
- 4xx(클라이언트 에러): 클라이언트의 요청에 오류가 있음
- 5xx(서버 에러): 서버의 요청 처리 중 오류가 발생
자세한 상태 코드에 대한 설명은 여기에서 보실 수 있습니다.
HTTPS (Hyper Text Transfer Protocol Secure)
HTTPS는 HTTP의 보안 취약점을 해결하기 위한 프로토콜입니다. HTTP는 데이터를 텍스트 그대로 주고받습니다. 이는 도청(Sniffing), 변조(Tampering), 위장(Spoofing)의 위험에 노출되는 문제가 있습니다. 그래서 암호화, 인증을 도입한 TLS를 이용한 HTTPS가 나오게 되었습니다. HTTPS는 HTTP와 다르게 443 포트를 사용합니다.
암호화
HTTPS는 암호화를 통해 주고받는 데이터를 암호화 합니다. 우선 암호화 이해를 위해서 대칭키 암호화와 비대칭키 암호화에 대해 먼저 간략하게 설명하겠습니다.
대칭키 암호화 (Symmetric Key)
대칭키 암호화는 암호화 하는 키와 복호화 하는 키가 같은 암호화 입니다. 그래서 암호화/복호화의 속도가 빠르지만, 키가 탈취되면 정보가 그대로 노출된다는 단점이 있습니다.
비대칭키 암호화 (Asymmetric Key)
비대칭키 암호화는 암호화 하는 키와 복호화 하는 키가 1개의 쌍으로 구성되는 암호화 입니다.
A와 B 두 키가 한 쌍일 때, A키로 암호화 한 데이터는 B키로만 복호화가 가능하고, 반대의 경우도 마찬가지입니다.
실제로는 다른 사람에게 공개하는 공개키, 생성자 본인만 가지는 개인키로 구성됩니다.
하나의 키가 탈취되어도 복호화가 불가능 하다는 장점이 있지만, 연산 속도가 오래 걸린다는 단점이 있습니다.
HTTPS는 두 암호화 방식을 같이 사용(Hybrid)합니다. 처음 Handsake 과정에는 비대칭키를 이용해 검증하고, 서버와 클라이언트가 서로 인증되면 대칭키를 주고받아 이후 연결에는 대칭키를 사용해서 요청-응답 속도를 높입니다.
HTTPS 동작 과정
HTTPS는 HTTP에 TLS가 추가된 형태이기 때문에 TCP의 Handsake 과정은 그림에 없지만, 가장 먼저 진행되는건 HTTP와 같습니다. 그림에 있는 Handsake는 HTTPS의 Handsake입니다. TCP의 3-Way Handaske와는 별개입니다.
1. TLS Handsake
TLS Handsake는 TCP Handsake가 완료되면 진행됩니다. 구글에 검색해보니 HTTPS Handaske도 설정에 따라 조금씩 다른거 같아서 일단 찾은 내용들을 조합해서 설명하겠습니다.
1. Negotiation
Client Hello
클라이언트가 서버에게 Handsake를 위한 정보를 전달하는 단계입니다.
지원하는 TLS 버전(Protocol Version), 지원하는 암호화 알고리즘(Cipher Suite List), 클라이언트 생성 32바이트 난수(Client Random), Session ID, SNI(Server Name Indication)이 해당합니다.
난수는 이후 대칭키를 만들때 사용됩니다.
Session ID는 복잡한 Handsake 과정을 반복하지 않기 위해 최초 Handsake인지 아닌지 판단하기 위한 정보입니다.
SNI는 어떤 도메인에 TLS를 수행할지 명시하는 부분입니다.
Server Hello
서버가 Client Hello에 대해 응답하는 부분입니다.
Client Hello와 형식은 거의 동일합니다.
클라이언트에서 제시한 TLS 버전 중 선택한 버전(Selected Protocol), 사용 가능한 암호화 방식 중 선택한 암호화(Selected Cipher Suite), 서버 생성 32바이트 난수(Server Random), Session ID가 해당합니다.
서버 난수도 대칭키 생성에 사용됩니다.
Session ID는 클라이언트가 보낸 Session ID를 검증하고, 없다면 새로운 Session ID를 생성해서 보냅니다.
2. Authentication
서버가 자신이 진짜임을 증명하고, 키 교화에 필요한 정보를 제공하는 단계입니다.
Server Certificate
서버의 SSL 인증서를 전달합니다.
인증서에 서버의 공개키가 포함되어 전달됩니다.
Server Key Exchange (Optional)
해당 단계는 있는 글도 있고 없는 글도 있는데, 찾아보니 방식에 따라 있기도 하고 없기도 한 단계라고 합니다.
ECDHE라는 키쌍을 만들어서 보내는 단계라고 합니다.
Server Hello Done
서버가 클라이언트에게 데이터 전송이 완료되었다는 알림입니다.
3. Key Exchange
클라이언트가 서버가 보낸 인증서를 검증하고, 실제 암호화 키를 생성하는 단계입니다.
인증서 검증
클라이언트는 서버가 보낸 SSL 인증서를 검증합니다.
서버가 보낸 SSL 인증서가 믿을만한 CA가 만든 인증서인지 브라우저에 내장된 CA 정보들을 이용해 검증을 진행합니다.
CA 정보는 대부분의 브라우저에 내장되어 있습니다.
만약 이 검증 과정에서 믿을만한 CA가 아니라는 사실을 알게되면 브라우저는 경고를 띄웁니다.
SSL 인증서를 직접 생성해서 적용해본 경험이 있는 분들이라면 분명 HTTPS 적용을 했는데 경고가 뜨는 경험을 해보셨을겁니다.
그 이유가 CA를 믿을 수 없다고 판단해서 입니다.
Client Key Exchange
클라이언트는 예비 마스터키(Pre-Master Secret)라는 48바이트 난수를 생성합니다.
pre-master secret을 서버의 공개키로 암호화 해서 서버에게 전달합니다.
pre-master secret은 서버의 공개키로 암호화 했기때문에 서버에서만 복호화가 가능한 상태가 됩니다.
Master Secret 생성
이 과정은 통신 과정은 아닙니다.
지금까지의 과정으로 서버와 클라이언트 모두 서버 난수, 클라이언트 난수, Pre-Master Secret을 가지게 되었습니다.
서버와 클라이언트는 3개의 값을 이용해 최종적으로 사용할 세션키(Master Secret)를 각자 계산합니다.
Change Cipher Spec & Finish
클라이언트가 생성한 키를 이용해서 암호화 하겠다고 알리고 무결성을 확인하는 과정입니다.
이때 지금까지 주고받은 Handsake 메세지들의 해시값을 암호화 해서 전달합니다.
4. Completion
서버도 암호화를 검증하고 수락하는 단계입니다.
Change Cipher Spec & Finish
클라이언트의 암호화 알림을 받고 서버도 암호화 적용을 위해 검증하는 단계입니다.
서버 역시 지금까지 주고받은 Handsake 메세지들의 해시값을 암호화 해서 클라이언트로 보내고, 클라이언트가 복호화 해서 값이 일치함을 확인하면 Handsake가 완료됩니다.
2. Data Transfer
데이터를 주고받는 과정입니다. 이떄 Handsake때 생성한 대칭키(세션키, Master Secret)을 이용해서 암호화를 진행한 후 데이터를 송수신 하게 됩니다.
HTTP와 HTTPS에 대해서 알아봤습니다. 그러나 TLS 버전별 차이, HTTP 버전별 차이, SSL 인증서 구성 요소 등 설명하지 못한 부분도 많이 남아 있습니다. 해당 내용들은 추후에 다른 글에서 자세히 작성해 보겠습니다.


