안녕하세요! 웹 개발을 하다 보면 누구나 한 번쯤 거대한 벽처럼 느껴지는 주제가 있습니다. 바로 '로그인(인증/인가)'인데요. 구글링해서 어찌어찌 코드를 복붙해 구현하긴 했는데, 막상 "쿠키랑 세션의 차이가 뭐예요?", "왜 굳이 토큰을 써요?"라는 질문을 받으면 말문이 턱 막히곤 합니다.
그래서 오늘부터 총 7편에 걸쳐 웹 인증과 보안의 모든 것을 쉽고 깊게 털어보려고 합니다. 그 대망의 첫 번째 시간! 우리가 왜 로그인을 구현하기 위해 이토록 고생해야 하는지, 그 근본적인 이유인 HTTP의 특징과 쿠키, 세션에 대해 완벽하게 정리해 드리겠습니다. 준비되셨나요? 출발해 봅시다!
1. 웹 서버는 금붕어다? (HTTP의 무상태성)
웹 브라우저와 웹 서버는 서로 대화할 때 HTTP(HyperText Transfer Protocol)라는 통신 규약을 사용합니다. 그런데 이 HTTP 녀석에게는 아주 치명적(?)인 두 가지 특징이 있습니다. 바로 비연결성(Connectionless)과 무상태성(Stateless)입니다.
- 비연결성(Connectionless): 클라이언트가 요청(Request)을 보내고 서버가 응답(Response)을 마치면, 둘 사이의 연결을 쿨하게 뚝 끊어버립니다. 서버 자원을 아끼기 위한 아주 효율적인 방법이죠.
- 무상태성(Stateless): 통신이 끊어졌기 때문에, 서버는 클라이언트의 이전 상태를 전혀 기억하지 못합니다.
이게 왜 문제일까요? 쇼핑몰을 예로 들어보겠습니다. 제가 아이디와 비밀번호를 치고 로그인을 했습니다. 서버는 "오, 환영합니다!" 하고 응답을 줍니다. 그리고 장바구니에 상품을 담으려고 클릭하는 순간! 서버는 다시 묻습니다. "누구세요? 로그인부터 하세요."
서버 입장에서는 방금 전 로그인 요청을 한 사람과, 지금 장바구니 버튼을 누른 사람이 같은 사람인지 기억할 방법이 없는 겁니다. 매번 요청을 보낼 때마다 아이디와 비밀번호를 같이 보내야 한다면 너무 끔찍하겠죠? 이 '금붕어 같은 웹 서버'에게 나라는 존재를 기억하게 만드는 기술, 그것이 바로 웹 인증의 시작입니다.

2. 첫 번째 해결책, 내 정보는 내가 챙긴다: 쿠키(Cookie)
서버가 나를 기억하지 못한다면, 내가 서버에게 갈 때마다 "저 아까 그 사람이에요!" 하고 증표를 보여주면 되지 않을까요? 이 아이디어에서 출발한 것이 바로 쿠키(Cookie)입니다.
쿠키의 동작 방식은 놀라울 정도로 단순합니다.
- 사용자가 로그인을 하면 서버가 확인 후, 응답 헤더의 Set-Cookie에 사용자의 정보(이름, 등급 등)를 담아서 보내줍니다.
- 브라우저는 이 쿠키를 자신의 로컬 저장소에 고이 모셔둡니다.
- 이후 브라우저가 서버에 어떤 요청을 하든, 약속이라도 한 듯이 무조건 요청 헤더(Cookie)에 이 쿠키를 찰싹 붙여서 같이 보냅니다.
서버는 요청에 딸려온 쿠키를 읽고 "아, 아까 로그인한 김개발 님이시군요!" 하고 알아차리게 되는 것이죠.
🚨 하지만 쿠키에게는 너무나 치명적인 단점이 있습니다. 가장 큰 문제는 보안입니다. 쿠키는 브라우저(클라이언트)에 저장되기 때문에 누구나 쉽게 열어볼 수 있고, 심지어 조작도 가능합니다. 만약 쿠키에 user_role=member라고 적혀있는데, 이걸 브라우저 개발자 도구에서 user_role=admin으로 쓱 바꾸면 어떻게 될까요? 끔찍한 대참사가 일어날 수 있습니다. 또한 브라우저마다 쿠키 저장 용량(보통 4KB)에 제한이 있어서 많은 정보를 담기에도 부적합하죠.
3. 두 번째 해결책, 중요한 정보는 서버가 보관한다: 세션(Session)
쿠키를 그냥 쓰자니 너무 불안합니다. 그래서 개발자들은 머리를 맞대고 고민했습니다. "중요한 정보는 클라이언트(브라우저)한테 주지 말고, 그냥 서버 메모리에 안전하게 숨겨두자!" 그렇게 등장한 것이 세션(Session)입니다.
사실 세션도 내부적으로는 쿠키를 사용합니다. 단지 쿠키 안에 무엇을 담느냐가 다를 뿐이죠.
- 사용자가 로그인을 하면 서버는 유저 정보를 확인하고, 서버 측 메모리(또는 DB)에 해당 유저의 공간을 하나 만듭니다.
- 그리고 이 공간에 접근할 수 있는 알 수 없는 난수 형태의 임시 열쇠(예: Session ID = A1B2C3D4...)를 발급합니다.
- 서버는 응답 헤더를 통해 진짜 개인정보 대신, 이 Session ID만 쿠키에 담아서 클라이언트에게 줍니다.
이제 클라이언트는 요청할 때마다 이 Session ID가 담긴 쿠키를 서버로 보냅니다. 서버는 쿠키에서 Session ID를 꺼내고, 자신의 메모리 안에서 그 열쇠에 맞는 유저 정보를 찾아냅니다. 이렇게 하면 클라이언트에는 복잡한 암호문(Session ID)밖에 없으니, 해커가 쿠키를 훔쳐보더라도 이 사람이 누군지 알 길이 없습니다. 보안성이 훨씬 높아진 것이죠!

4. 실무의 벽: 사용자가 많아져서 서버를 늘려야 한다면? (Scale-out)
자, 여기까지가 일반적인 전공 수업이나 학원에서 배우는 내용입니다. 하지만 우리는 실무 개발자잖아요? 실무에서는 여기서 끝이 아닙니다. 여기서부터 조회수를 끌어올릴 진짜 트러블슈팅 이야기가 시작됩니다.
여러분이 만든 서비스가 대박이 났습니다! 동시 접속자가 수만 명이 되어서, 기존 서버 1대(Server A)로는 버틸 수가 없어 서버를 2대(Server B, Server C) 더 추가했습니다. 이것을 서버를 옆으로 늘린다고 해서 스케일 아웃(Scale-out)이라고 부릅니다. 그리고 그 앞에는 트래픽을 분산시켜 주는 로드밸런서(Load Balancer)를 달아두었죠.
그런데 여기서 엄청난 문제가 발생합니다. 바로 '세션 불일치(Session Inconsistency)' 문제입니다.
제가 Server A에 배정되어 로그인을 성공했습니다. 제 세션 정보는 Server A의 메모리에 저장되어 있겠죠? 그런데 다음 페이지로 이동하려고 클릭했더니, 이번엔 로드밸런서가 저를 Server B로 연결해 버렸습니다. Server B는 제 세션 정보가 없기 때문에 또다시 매정하게 말합니다. "누구세요? 로그인부터 하세요." 사용자는 페이지를 이동할 때마다 로그아웃이 되는 최악의 경험을 하게 됩니다.
5. 세션 불일치 문제를 해결하는 실무 아키텍처
이 거대한 문제를 실무에서는 어떻게 해결할까요? 대표적으로 두 가지 방법이 있습니다.
- Sticky Session (스티키 세션): 이름 그대로 끈적끈적하게 사용자를 한 서버에 딱 붙여버리는 방법입니다. 로드밸런서가 사용자의 IP나 쿠키를 확인해서 "아, 너는 아까 Server A에서 로그인했지? 앞으로 계속 Server A로만 가!" 하고 길을 지정해 줍니다.
- 단점: 구현은 쉽지만 특정 서버에만 트래픽이 몰릴 수 있고, 만약 Server A가 다운되면 그 서버에 있던 모든 사람의 로그인 상태가 날아가 버립니다.
- Session Clustering (세션 클러스터링)과 Redis의 등장 (🌟 실무 표준): 가장 우아하고 현대적인 해결책입니다. 각 서버(Tomcat, Node.js 등)의 메모리에 세션을 각자 저장하지 않고, 세션만 전문적으로 저장하는 별도의 공통 저장소를 하나 따로 두는 겁니다. 이때 가장 많이 사용되는 기술이 바로 Redis(레디스)라는 인메모리(In-Memory) 데이터베이스입니다. 이제 Server A, B, C는 유저가 접근하면 각자의 메모리를 뒤지지 않고, 중앙에 있는 Redis에게 "얘 세션 있어?" 하고 물어봅니다. 서버가 100대로 늘어나든, 특정 서버가 다운되든 전혀 문제없이 세션이 유지되는 완벽한 아키텍처가 완성되는 것이죠!

마치며: 세션도 완벽하지 않다?
오늘은 HTTP의 근본적인 한계를 극복하기 위한 쿠키와 세션의 역사, 그리고 실무에서 마주치는 서버 확장(Scale-out) 시의 세션 불일치 문제까지 깊게 알아보았습니다.
"Redis를 쓰면 완벽하네요! 그럼 로그인 구현은 이걸로 끝인가요?"
아쉽게도 아닙니다. Redis를 도입하면 세션 문제는 해결되지만, 서비스 규모가 카카오나 네이버처럼 거대해질수록, 또는 모바일 앱이나 외부 API 통신이 많아질수록 '매번 서버에 세션을 확인해야 하는 비용(네트워크 통신 비용)' 자체가 엄청난 부담으로 다가오기 시작합니다.
그래서 현대의 모던 웹/앱 개발 생태계는 세션을 버리고 *새로운 패러다임'으로 넘어가게 됩니다. 그것이 바로 다음 시간에 다룰 주인공, JWT(JSON Web Token)입니다.
과연 JWT는 세션의 어떤 문제를 해결하기 위해 등장했을까요? 다음 [2편] 모던 웹 인증의 핵심: JWT의 구조와 원리 편에서 그 흥미로운 비밀을 파헤쳐 보겠습니다. 기대해 주세요!
[실무 웹 인증과 보안 완벽 가이드 #02] 모던 웹 인증의 핵심: JWT(JSON Web Token) 구조와 원리, 그리고
안녕하세요! 지난 1편에서는 웹 서버의 '금붕어 같은 기억력(무상태성)'을 극복하기 위해 등장한 쿠키와 세션, 그리고 사용자가 많아졌을 때 서버를 확장(Scale-out)하면서 겪는 세션 불일치 문제와
code-bricks.tistory.com