웹 개발을 공부하다 보면 HTTP라는 용어를 정말 많이 접하게 된다. "HTTP 에러가 났다", "HTTP 요청을 보냈다" 등등...
오늘은 이 HTTP(Hypertext Transfer Protocol)가 무엇인지, 그리고 웹에서 어떻게 중요한 역할을 하는지 알아보겠다.
HTTP는 웹 기반 애플리케이션에서 정보를 주고받기 위한 가장 기본적인 통신 규약 중 하나이다. 마치 우리가 편지를 쓸 때 정해진 양식과 언어가 있는 것처럼, 웹 브라우저(클라이언트)와 웹 서버가 서로 대화하기 위한 약속이라고 생각하면 된다.
특히 웹 브라우저가 사용하는 언어인 HTML(Hypertext Markup Language)과 이름이 비슷한데, 이는 우연이 아니다. HTML로 작성된 웹 페이지와 같은 Hypertext 정보를 효율적으로 주고받기 위해 HTTP가 탄생했기 때문이다.
더 자세히 들어가 보면, HTTP는 OSI 7계층 모델의 가장 꼭대기에 위치한 응용 계층(Application Layer) 프로토콜이다. 우리가 웹 서핑을 하면서 가장 직접적으로 경험하는 계층이라고 할 수 있다.
HTTP는 클라이언트-서버 구조를 따른다. 마치 커피숍 손님과 점원처럼 역할이 나뉘어 있다.
클라이언트 (Client): 정보를 요청하는 주체 (예: 웹 브라우저)
서버 (Server): 요청에 따라 정보를 제공하는 주체 (예: 웹 서버)
손님이 점원에게 "아메리카노 한 잔 주세요"라고 요청(request)하면, 점원은 그 요청에 따라 커피를 만들어 응답(response)하는 것과 같은 방식입니다. 웹 브라우저가 웹 페이지를 보고 싶을 때 서버에 HTTP 요청을 보내고, 서버는 해당 웹 페이지의 HTML, CSS, JavaScript 등의 파일을 HTTP 응답으로 보내주는 것이죠.
HTTP 요청 메시지와 응답 메시지는 특정한 헤더(header)와 그 값들로 구성된다. 마치 카페에서 주문서에 메뉴, 사이즈, 옵션 등을 적는 것처럼, HTTP 메시지에도 필요한 정보들이 담겨 있다.
웹 브라우저의 개발자 도구 (F12)를 열고 네트워크(Network) 탭을 확인해 보자. 우리가 웹 사이트를 방문할 때 주고받는 수많은 HTTP 요청과 응답 메시지를 눈으로 직접 확인할 수 있다. 처음에는 복잡해 보일 수 있지만, 자주 사용되는 헤더와 값들은 정해져 있어서 익숙해지면 어렵지 않다.
HTTP 요청 메시지를 "제대로" 작성하기 위해서는 서버가 어떤 형식과 값을 원하는지 알아야 한다. 이때 필요한 것이 바로 API 문서이다. API 문서는 마치 카페의 메뉴판처럼, 어떤 메뉴를 주문할 수 있는지, 각 메뉴에는 어떤 옵션이 있는지 상세하게 안내해 주는 문서다. 개발자들은 이 API 문서를 참고하여 서버와 정확하게 통신할 수 있는 HTTP 요청을 만들 수 있다.
HTTP는 몇 가지 중요한 특징을 가지고 있다.
1. 무상태성 (Stateless)
HTTP는 무상태성(Stateless)이라는 특징을 가진다. 서버는 클라이언트의 이전 요청이나 응답을 기억하지 못한다. 마치 카페에서 손님이 "아메리카노 한 잔 주세요"라고 주문한 후에, 다시 "아이스로 바꿔주세요"라고 말했을 때, 점원은 이전에 어떤 커피를 주문했는지 기억하지 못하는 것과 같다.
따라서 매번의 요청은 독립적으로 처리되어야 한다. 이전의 상태를 유지하려면 별도의 메커니즘(예: 쿠키, 세션)이 필요하다. 이러한 무상태성 덕분에 서버는 여러 클라이언트의 요청을 효율적으로 처리할 수 있으며, 서버 확장에 유리한 구조를 가질 수 있다.
2. 비연결성 (Connectionless)
HTTP는 기본적으로 요청과 응답이 완료되면 연결을 끊는 비연결성(Connectionless)을 가진다. 이는 불필요한 네트워크 자원 소모를 줄이기 위한 전략이다. 마치 전화를 걸어 용건만 말하고 끊는 것과 비슷하다고 생각할 수 있다. 통화 연결 자체가 유지되는 동안에는 요금이 부과될 수 있지만, 연결을 끊으면 비용이 발생하지 않는 것과 비슷하다.
하지만 잦은 요청이 필요한 경우에는 매번 연결을 맺고 끊는 과정이 오히려 비효율적일 수 있다. 이러한 문제를 해결하기 위해 HTTP 1.1에서는 지속 연결(Persistent Connection)이라는 개념이 도입되었다. 이는 한 번 연결을 맺으면 여러 번의 요청과 응답을 처리한 후 연결을 종료하는 방식이다.
3. 지속 연결과 파이프라이닝, 그리고 멀티플렉싱
지속 연결은 효율성을 높였지만, 여전히 요청과 응답이 순차적으로 처리되는 동기적인 방식이라 지연이 발생할 수 있다. 이를 개선하기 위해 HTTP 1.1에서는 파이프라이닝(Pipelining)이라는 기술이 등장했다. 이는 여러 개의 요청을 순서대로 보내고, 응답은 다시 순서대로 받는 방식이다. 마치 공장에서 여러 개의 작업을 순서대로 처리하는 컨베이어 벨트와 비슷하다고 할 수 있다.
하지만 파이프라이닝에도 응답 지연과 같은 한계가 있었다. 이러한 한계를 극복하고 더욱 효율적인 통신을 위해 HTTP 2.0에서는 멀티플렉싱(Multiplexing)이라는 기술이 도입되었다. 멀티플렉싱은 하나의 연결을 통해 여러 개의 요청과 응답을 동시에 비동기적으로 처리할 수 있게 해준다. 마치 여러 개의 택배를 하나의 트럭으로 동시에 운송하는 것과 같다고 생각하면 된다. 덕분에 웹 통신은 훨씬 더 빠르고 효율적으로 이루어질 수 있게 되었다.
- 무상태성(Stateless): 서버는 이전 요청을 기억하지 않는다.
- 비연결성(Connectionless): 요청과 응답 후 연결을 끊는다. (HTTP 1.1의 지속 연결로 개선)
- 파이프라이닝 (HTTP 1.1): 여러 요청을 순서대로 보내고 응답을 순서대로 받는다.
- 멀티플렉싱 (HTTP 2.0): 하나의 연결로 여러 요청과 응답을 비동기적으로 처리하여 효율성을 극대화한다.
기존 HTTP에 보안 갑옷을 덧입힌 게 바로 HTTPS(Hypertext Transfer Protocol Secure)다. HTTP가 하던 일 그대로 하면서 SSL(Secure Sockets Layer)이나 더 최신인 TLS(Transport Layer Security)라는 암호화 방식으로 주고받는 정보를 꽁꽁 숨겨버리는 것이다. HTTPS 주소는 http:// 대신 https://로 시작하고, 보통 443번 포트를 쓴다.
HTTPS 핵심은 암호화다. 데이터를 암호화해서 누가 중간에서 훔쳐봐도 뭔 소린지 모르게 만들어 버리는 것이다. HTTPS는 여러 암호화 방식을 섞어서 튼튼한 보안을 제공하는 것이다.
공개키랑 비밀키: 이건 마치 자물쇠랑 열쇠 같은 것이다. 공개키는 누구나 볼 수 있는 자물쇠고, 이 자물쇠로 잠근 정보는 비밀키 가진 사람만 열 수 있는 것이다. 암호화랑 복호화에 쓰는 키가 다르다는 게 특징이다.
대칭키 암호화: 암호화랑 복호화에 똑같은 비밀키 쓰는 방식이다. 둘만 아는 암호로 대화하는 거랑 똑같은 것이다. 빠르고 효율적인데, 비밀키를 안전하게 주고받는 게 중요하다.
비대칭키 암호화: 암호화랑 복호화에 서로 다른 키 쓰는 것이다. 암호화할 땐 공개키를 쓰고, 풀 땐 비밀키를 쓰는 것이다. 비밀키는 혼자만 갖고 있고, 공개키는 막 뿌려도 된다. 키 교환 문제 해결이다.
인증 기관(CA): 우리가 들어가려는 웹사이트가 진짜 믿을 만한 곳인지 보증해 주는 믿음직한 회사다. CA는 웹사이트 정보 확인하고, 자기네 비밀키로 암호화해서 인증서를 만들어 주는 것이다. 우리 웹 브라우저는 CA 공개키를 미리 알고 있으니까, 서버가 준 인증서를 CA 공개키로 풀어보고 진짜인지 확인하는 것이다. CA 비밀키로 잠근 건 CA 공개키로만 풀리니까 풀리면 믿을 수 있는 것이다.
웹사이트, CA랑 계약: 웹사이트가 자기 공개키랑 정보들을 믿을 만한 인증 기관(CA)에 주고 관리해 달라고 하는 것이다.
인증서 발급: CA는 정보 확인하고 자기네 비밀키로 웹사이트 정보랑 공개키 묶어서 인증서 만들어 주는 것이다.
CA 공개키 제공: 인증 기관은 웹 브라우저 같은 프로그램에 자기네 공개키를 미리 넣어두거나 안전하게 알려주는 것이다.
클라이언트 접속 시도: 우리가 HTTPS 웹사이트 들어가려고 하면, 서버는 자기 인증서를 우리한테 보내는 것이다.
인증서 확인: 우리 브라우저는 미리 알던 CA 공개키로 서버가 준 인증서를 풀어보는 것이다. 풀리면 진짜 CA가 인증한 곳이구나 믿는 것이다.
대칭키 암호화 시작: 이제 안전하게 서버 공개키 얻었으니까, 이걸로 임시로 쓸 대칭키를 암호화해서 서버한테 다시 보내는 것이다.
대칭키 획득: 서버는 자기 비밀키로 우리가 보낸 암호화된 대칭키를 풀어보는 것이다.
안전한 통신 시작: 이제 우리랑 서버 둘 다 똑같은 대칭키를 알게 됐으니까, 이걸로 주고받는 모든 데이터를 암호화하고 풀면서 안전하게 통신하는 것이다.
