HTTP는 HyperText Transfer Protocol의 약자로서, 말 그대로 하이퍼텍스트를 포함한 문서를 인터넷 상에서 주고받기 위한 통신 규약이다.
일반 텍스트와 달리 하이퍼링크들을 가지고 있어 페이지 간 이동을 가능하게 해주는 텍스트
HTML이 이러한 하이퍼텍스트를 표현하기 위한 마크업 언어라고 보면 되고, 이를 포함하는 페이지를 인터넷 상에서 주고받을 때 바로 HTTP를 사용하는 것이다.
HTTP의 특징은 다음과 같다.
- 클라이언트(보통 웹 브라우저)와 서버 간의 요청(request)와 응답(response)를 통해 작동한다.
- 다양한 종류의 데이터(html, css, javaScript, png, gif, mp4, ...)를 전송할 수 있도록 설계된 프로토콜이다.
- 웹 페이지에 포함된 각 구성 요소(이미지, 텍스트, HTML, 영상 등)는 대부분 개별적인 HTTP 요청을 통해 웹 서버로부터 요청된다. 따라서 가끔 글이 먼저 보이고 이미지가 나중에 보일 때가 있는 것이다.
- 일반적으로 TCP/IP 프로토콜 기반으로 동작한다.
- 데이터를 주고받기 위해 행해지는 각각의 데이터 요청이 서로 독립적으로 관리된다. 즉 이전 데이터 요청과 다음 데이터 요청이 서로 관련이 없다.
HTTP는 요청과 응답으로 구성된다고 했는데, 각각의 메시지 구성에 대해 한 번 알아보자.

HTTP 요청 메시지는 위와 같이 start line, headers, body로 구성된다.
각각의 구성 요소에 대해 알아보자.
HTTP Request Message의 시작 라인으로서, 3가지 부분으로 구성된다.
GET /test.html HTTP/1.1
순서대로 HTTP method, Request target, HTTP version이며, 각각에 대해 알아보자.
- HTTP method
요청의 의도를 담고 있는 부분으로,GET,POST,PUT,DELETE등이 있다.GET은 존재하는 자원에 대한 요청,POST는 새로운 자원을 생성,PUT은 존재하는 자원에 대한 변경,DELETE는 존재하는 자원에 대한 삭제와 같은 기능을 가지고 있다.- Request target
HTTP Request가 전송되는 목표 주소이다. URL의 구성에서 경로 부분만 포함된다.- HTTP version
말 그대로 사용되는 HTTP의 버전이다. 이 버전에 따라 요청 메시지 구조나 데이터가 다를 수 있어서 이를 명시한다.
해당 request에 대한 추가 정보를 담고 있는 부분이다.
구성 요소에 대해 알아보자.
✔️ Host
요청하려는 서버 호스트 이름과 포트번호를 담는 헤더이다. 어떤 서버에 요청을 보내는지 명확히 하기 위해 필요하다.Host: www.example.com:80✔️ User-Agent
요청을 보내는 클라이언트 프로그램(예: 브라우저) 의 정보를 담는다. 서버는 이 정보를 보고 해당 클라이언트에 최적화된 응답 데이터를 줄 수 있다.User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...✔️ Referer
사용자가 현재 요청을 보내기 직전에 머물렀던 웹페이지의 주소(URL) 이다.Referer: https://www.google.com/✔️ Accept
클라이언트가 처리 가능한 콘텐츠 타입(MIME type) 을 명시한다. 서버는 이 목록에 맞는 형식으로 데이터를 응답한다.Accept: text/html, application/json✔️ If-Modified-Since
여기에 지정된 시간 이후로 리소스가 변경된 경우에만 응답을 받도록 요청한다. 캐싱에 사용되며, 페이지가 바뀌지 않았다면 응답을 줄 필요가 없다.If-Modified-Since: Wed, 05 Jul 2023 10:00:00 GMT
근데 요청이 먼저인데 If-Modified-Since에 시간은 어떻게 담기게 되었는지 에 의문이 들어 If-Modified-Since에 시간이 담기는 과정에 대해 알아보았다.
If-Modified-Since에 시간이 담기는 과정은 다음과 같다.
예를 들어 브라우저가 이미지나 HTML을 처음 받아올 때, 응답 헤더에 다음과 같은 값이 포함된다.
Last-Modified: Wed, 03 Jul 2024 14:00:00 GMT
이 값을 캐시에 저장해 둔다.
GET /logo.png HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 03 Jul 2024 14:00:00 GMT
서버 내부에 있는 logo.png 파일의 수정 시간(파일 시스템 기준 혹은 DB 기록 등)을 확인한다.
그 시간이 요청에 담긴 If-Modified-Since보다 더 최근이면, 새로운 파일을 보내준다. 이 경우 200 OK라고 응답 메시지에 포함된다.
그 시간이 요청보다 같거나 이전이면, 바뀐 게 없다고 응답한다.
이 경우 304 Not Modified라고 응답 메시지에 포함된다.
✅ 변경 O (갱신이 필요한 경우):
HTTP/1.1 200 OK
Last-Modified: Wed, 05 Jul 2024 10:00:00 GMT
Content-Type: image/png
...
✅ 변경 X (캐시 사용이 가능한 경우):
HTTP/1.1 304 Not Modified
✔️ Authorization
서버에 요청할 때 필요한 인증 토큰을 담는 헤더이다. 주로 로그인한 사용자임을 증명할 때 사용된다.Authorization: Bearer abc123token✔️ Origin
요청을 보낸 출처(도메인 + 포트) 를 나타낸다. 이 값이 서버의 도메인과 다르면, CORS 정책에 따라 에러가 발생할 수 있다.Origin: http://localhost:3000✔️ Cookie
클라이언트에 저장된 쿠키 값들을 key=value 형태로 서버에 전송한다. 로그인 상태 유지, 사용자 설정 저장 등에 사용된다.Cookie: sessionId=abc123; theme=dark
HTTP Request가 전송하는 데이터를 담고 있는 부분이다.
전송하는 데이터가 없다면 body 부분은 비어 있다.
보통 POST 요청일 경우, HTML 폼 데이터(웹사이트에서 <form> 태그를 이용해 사용자로부터 입력받은 정보)가 포함되어 있다.

HTTP Response Message는 request와 동일하게 공백을 제외하고 status, header, body의 3가지 부분으로 나뉘어진다.
HTTP Response의 상태를 간략하게 나타내주는 부분으로서, HTTP version, Status Code, Status Text의 3가지 부분으로 구성된다.
HTTP/1.1 200 OK

Request의 headers와 거의 동일하다.
다만 response에서만 사용되는 header 값들이 있다.
예를 들어, User-Agent 대신에 Server 헤더가 사용된다.
Request의 body와 일반적으로 동일하다.
Request와 마찬가지로 모든 response의 body가 비어 있지는 않다.
데이터를 전송할 필요가 없을 경우 body가 비어있게 된다.
가장 초기에 사용되었던 HTTP의 버전이다.

HTTP는 TCP 연결 위에서 동작한다는 것은 다들 알고 있을 것이다. 그림에서 보다시피 HTTP 1.0 버전은 요청이 갈 때마다 새로운 TCP 연결을 수립해야 하는 방식이었다.
즉, 클라이언트가 서버와 Connection 을 맺기 위해 DNS 조회, TCP 3-way handshake, SSL/TLS handshake 같이 네트워크 지연 시간을 늘리는 행위를 1개의 요청 마다 반복적으로 했어야 했다.
HTTP 1.0에서의 단점을 보완하기 위해 HTTP 1.1에서는 keepalive 라는 기능이 추가되었다.

이 기능은 위 그림처럼 한 번 연결이 수립되면, 데이터 교환이 끝날 때까지 이를 유지하고 데이터 교환이 모두 끝나면 연결을 끊는 방식이다.
이 연결 위에서, 파이프라이닝(Pipelining) 이라고 하여 응답을 기다리지 않고 여러 HTTP 요청을 연속해서 보낼 수 있게 되었다.
이렇게 하나의 TCP 연결을 통해 여러 개의 요청과 응답을 수행할 수 있게 되었다.
하지만 HTTP 1.1에는 치명적인 단점이 있었는데, 이는 요청이 들어온 순서대로 응답을 해야 한다는 것이었다. 클라이언트 측에서 응답을 받을 때, 어떤 요청에 대한 응답인지 구분할 방법이 없었기 때문이다.
따라서 요청 1, 2, 3이 순서대로 들어왔다고 했을 때, 요청 1에 대한 처리가 끝날 때 까지 요청 2, 3에 대한 처리가 완료되었더라도 이는 응답받지 못한다. 이를 HOLB(Head Of Line Blocking)이라고 불리며, 한 요청에 대한 처리가 오래 걸리면 그 다음 응답이 지연된다는 것을 뜻한다.
HTTP 1.1 에서 메시지를 텍스트로 보냈다면,
HTTP 2.0에서는 header 정보가 들어갈 header frame, body 정보가 들어갈 body frame 이란 데이터 단위를 만든다.
이렇게 1개의 메시지는 1 or 2개의 HEADER frame 과 0개 이상의 DATA frame 으로 나뉘어서 전송된다.
그리고, 이렇게 나뉜 각 frame 들을 구분하고자 Stream Sequence 라는 번호를 frame 에 붙인다.
HTTP 1.1는 클라이언트가 각 요청에 대한 응답을 구분할 방법이 없어 서버 측에서 요청이 들어온 순서대로 응답했다면, HTTP 2.0에서는 Stream Sequence를 통해 클라이언트가 각 요청에 대한 응답을 구분 할 수 있게 되어 응답이 요청 순서대로 처리되지 않아도 무방하게 된 것이다.

이처럼 HTTP/2.0 은 스트림이라는 개념을 도입해서 파이프라이닝의 단점을 멀티플렉싱(multiplexing) 으로 극복하였다.
하지만, 여전히 TCP Connection 위에서 frame 들을 주고 받았기 때문에, TCP 에서 발생하는 HOLB를 해결할 순 없었다.
예를 들어, 두 번째 사진에서 stream2 header 의 패킷이 손실이 되었다면 해당 stream2 header 는 손실된 패킷이 올 때까지 기다리게 되고, 그 뒤에있는 stream 1 data, stream 3 data, stream 2data 는 여전히 기다리게 되었다.
즉 multiplexing 은 Application Layer 에서의 HOLB는 해결했지만 Transport Layer 에서의 HOLB는 여전히 문제가 되었다.
HTTP 2.0의 HOLB는 TCP의 특성상 발생했기 때문에, HTTP 3.0에서는 TCP에 의존하지 않고, UDP에 기반한 QUIC 프로토콜을 사용하게 되었다.
따라서 HTTP 2.0과는 달리, HTTP 3.0에서는 각 스트림이 독립적일 수 있게 되었다.
위 사진에서 TCP 연결 기반인 HTTP 2.0에서는 패킷 1이 손상되면 패킷 2~8이 모두 blocking 되지만, UDP 기반의 HTTP 3.0에서는 패킷 2, 3만 blocking 된다.
HyperText Transfer Protocol Secure의 약자로, HTTP의 보안 버전을 의미한다.
기존 HTTP 통신은 데이터들을 암호화되지 않은 상태의 평문으로 주고받았다. 따라서 아이디/비밀번호, 카드 정보, 채팅 내용 등 이런 민감한 정보도 그냥 읽을 수 있게 네트워크에 떠다녔던 것이다.
그렇기 때문에 누구든지 네트워크를 가로채면 정보를 훔칠 수 있었고, 중간자 공격·피싱 등에 취약했다.
따라서 HTTPS에서는 TSL 혹은 SSL이라는 프로토콜을 사용해 데이터를 안전하게 주고받을 수 있게 되었다.

해당 프로토콜은 보안 계층이라는 독립적인 계층을 만들어, 위와 같이 전송 계층인 TCP와, 응용 계층인 HTTP 사이에 속하게 된다.
즉, TLS는 TCP 연결이 설정된 이후 그 위에서 안전한 통신을 할 수 있게 만드는 계층인 셈이다. 그래서 HTTPS는 TCP 연결 → TLS 암호화 → HTTP 데이터 전송 이 순서로 이루어진다.
TLS 는 SSL의 업데이트 버전으로 SSL의 최종버전인 3.0과 TLS의 최초버전의 차이는 크지않으며, 이름이 바뀐것은 SSL을 개발한 Netscape가 업데이트에 참여하지 않게 되어 소유권 변경을 위해서였다고 합니다.(이름 변경)
결과적으로 TLS는 SSL의 업데이트 버전이며 명칭만 다르다고 볼 수 있습니다.
이러한 역사 때문에 TLS와 SSL라는 용어는 함께 사용되는 경우가 많으며, 같은 의미의 단어라도 보아도 무방할 것 같다.
그렇다면 TLS에서는 어떤 방식을 통해 암호화를 진행하게 될까?
결론부터 말하자면 공개 키 방식과 대칭 키 방식을 함께 사용하여 데이터를 암호화한다.
두 가지 방식에 대해 알아보자.
공개키 방식(Asymmetric Key Cryptography)은 데이터를 안전하게 전송하고 인증하는 데 사용된다. 이 방식은 두 개의 서로 다른 키를 사용하여 데이터를 암호화하고 복호화하는 방법을 기반으로 한다. 이 두 개의 키는 공개키(public key)와 개인키(private key)라고 불린다.
✔️ 공개 키
공개키는 누구나 볼 수 있고, 누구나 사용할 수 있는 키다. 데이터를 암호화하는 데 사용되며, 공개 키로 암호화된 데이터는 개인 키로만 해독할 수 있다.
✔️ 개인 키
개인키는 공개되면 안되는 비밀 키로서 소유자만 알고 있어야 한다. 개인키는 보안이 매우 중요하며, 타인과 공유해서는 안된다.
공개 키 방식에서, 데이터 송신자는 원래 알고 있던 데이터 수신자의 공개키를 이용해 데이터를 암호화한 후 전송한다. 수신자는 자신의 개인 키를 이용해 이를 복호화하여 원본 데이터를 얻을 수 있다.
대칭키 방식(Symmetric Key Cryptography)은 데이터를 암호화하고 복호화하는 데 동일한 키를 사용하는 방식이다.
암호화와 복호화에 동일한 키가 사용되기 때문에 키의 보안 관리가 매우 중요하다. 키가 노출되면 제 3자가 쉽게 데이터를 해독할 수 있으므로 키의 안전한 보관이 필요하다.
대칭키 방식은 암호화 알고리즘과 복호화 알고리즘이 동일하고, 알고리즘의 구조가 단순하므로 간단하고 빠른 처리 속도를 제공한다. 하지만 보안 키 관리와, 서버와 클라이언트 간 키 교환 문제로 인해 보안성이 요구되는 경우 대칭 키 방식을 적절히 사용하기 어려울 수 있다. 이러한 경우에는 공개 키 방식과 함께 사용하여 보다 안전하고 효율적인 보안을 제공하는 경우가 많다.
전반적인 동작 과정을 그림으로 나타내면 다음과 같다.

여기까지는 브라우저와 서버가 데이터를 주고받기 전에 미리 진행된 과정이다.
5 ~ 11은 클라이언트와 서버가 보안 연결을 맺기 전에 서로를 확인하고 암호화 방식 등을 정하는 과정이다.
이를 TLS handshake라고도 하는데, 좀 더 구체적으로 알아보자.

클라이언트가 서버로 Client Hello 메시지를 전송한다.
패킷 내에는 TLS Version, Client가 지원하는 암호화 방식, Client Random Data(클라이언트에서 생성한 난수로 대칭키를 만들 때 사용), Session ID, SNI(서버명) 가 포함된다.
✔️ Session ID
매번 연결할 때마다 Handshake 과정을 진행하는 것은 비효율적이니 최초 한번 전체 Handshake 과정을 진행하고 Session ID를 가진다. 후에는 이 Session ID를 사용해서 위 과정을 반복해서 진행하지 않는다.
✔️ SNI
SNI는 서버 이름 표시(Server Name Indication)의 약자이지만, SNI가 실제로 "표시하는" 것은 웹 사이트의 호스트 이름 또는 도메인 이름으로, 실제로 도메인을 호스팅하는 웹 서버의 이름과는 별개일 수 있다. 실제로 하나의 서버에서 여러 도메인을 호스팅하는 것이 일반적이며, 이 경우 가상 호스트 네임이라고 한다.
최초 Handshake에선 SessionID가 0이지만,
Handshake를 한번 진행하면 서버로부터 Session ID를 받는다.
클라이언트는 로컬에 저장해두고 다시 서버와 Handshake 과정을 맺을 일이 있다면 Session ID를 포함한 패킷을 전송한다.
서버에서는 전달받은 Session ID가 아직 유효하다면 동일한 Session ID를 다시 전송하고, 서버가 해당 Session ID를 모르거나 만료되었다면 새로운 Session ID를 생성해서 보낸다.
이 과정에서 최초 Handshake를 위해 진행한 작업들을 하지 않기 때문에 시간이 절약된다.
클라이언트가 보낸 Client Hello에 대한 서버의 응답이다.
TLS Version, 암호화 방식(Client가 보낸 암호화 방식 중에 서버가 사용 가능한 암호화 방식을 선택), Server Random Data(서버에서 생성한 난수, 대칭키를 만들 때 사용), SessionID(유효한 Session ID)를 포함한다.
서버의 인증서를 클라이언트에게 보내는 단계로 필요에 따라 CA의 Certificate도 함께 전송한다. 이 경우에는 이 서명이 신뢰할 수 있는 CA에 의해 발급된 것인지 검증하기 위함이다.
클라이언트는 이 패킷을 통해 서버의 인증서가 무결한지 검증한다.
서버가 클라이언트에게 보낼 메시지를 모두 보냈다는 뜻이다.
인증서가 무결한지 검증 되었으면 클라이언트의 난수와 서버의 난수를 조합하여 대칭키를 생성한다.
그리고 대칭키를 서버의 공개키로 암호화하고, 암호화한 정보를 서버에게 전송한다.
자세히 말하자면, 대칭키 생성에 필요한 정보를 서버에 제공한다. 이 정보를 pre-master secret 이라고 하며 절대 노출이 되어서는 안된다. pre-master secret은 난수를 조합하여 생성한 것이다.
이 값을 서버의 공개키로 암호화해서 전송하면 서버는 개인키로 복호화가 가능하다. 그렇게 되면 서로가 pre-master secret을 공유하게 된다. 이 값을 사용해서 세션에 사용될 키를 생성하게 되는데, 이 키가 바로 대칭키이다.
이제부터 전송되는 모든 패킷은 협상된 알고리즘과 키를 이용하여 암호화 하겠다고 알리는 메시지이다.
TLS Handshake를 성공적으로 마치고 종료한다.
https://www.cloudflare.com/ko-kr/learning/ssl/transport-layer-security-tls/
https://rachel-kwak.github.io/2021/03/08/HTTPS.html
https://blog.naver.com/skinfosec2000/222135874222
https://velog.io/@ajm0718/HTTPS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80
https://mark-kim.blog/HTTPS/
https://sunrise-min.tistory.com/entry/TLS-Handshake%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%A7%84%ED%96%89%EB%90%98%EB%8A%94%EA%B0%80
https://www.cloudflare.com/ko-kr/learning/ssl/what-is-sni/