본문 바로가기

Computer Science/NetWork

쿠키 vs 세션 vs 토큰(JWT) 완벽 정리 — 개념, 동작 원리, 코드, 보안까지

추천캐릭터 2026. 6. 29. 19:53
728x90

쿠키 vs 세션 vs 토큰(JWT) 완벽 정리 — 개념, 동작 원리, 코드, 보안까지

웹 개발에서 "로그인 상태를 어떻게 유지하는가?"는 가장 기본적이면서도 중요한 질문이다. HTTP는 기본적으로 무상태(Stateless) 프로토콜이라 요청마다 "나 누구예요"를 다시 알려줘야 한다.

이 문제를 해결하는 세 가지 방식이 쿠키, 세션, 토큰(JWT)이다. 이 글에서는 각각의 개념, 동작 원리, 실전 코드, 보안 주의사항까지 한 번에 정리한다.


한눈에 보는 비교표

구분 쿠키(Cookie) 세션(Session) 토큰(JWT)
저장 위치 클라이언트(브라우저) 서버(메모리/DB) 클라이언트(브라우저)
식별 방식 Cookie 헤더로 키-값 전달 JSESSIONID 쿠키로 세션 조회 Authorization 헤더로 토큰 전달
수명 Max-Age/Expires 지정 유휴 시간 초과 시 만료 토큰 내 exp 클레임
서버 부담 없음 세션 저장소 필요 없음 (Stateless)
확장성 좋음 서버 늘리면 세션 공유 필요 좋음
보안 위험 XSS, 탈취 세션 고정 공격 토큰 탈취 시 만료까지 유효
주 용도 아이디 기억, 다크모드 로그인 상태, 장바구니 API 인증, SPA, 마이크로서비스

1. 쿠키(Cookie) — 브라우저가 들고 다니는 메모

개념

서버가 브라우저에 "이거 저장해둬"라고 건네는 작은 데이터다. 브라우저는 이후 같은 서버에 요청할 때마다 쿠키를 자동으로 함께 보낸다.

동작 흐름

1. 브라우저 → 서버: 로그인 요청
2. 서버 → 브라우저: 응답 + Set-Cookie: rememberId=hong
3. 이후 모든 요청: 브라우저가 Cookie: rememberId=hong 자동 전송

쿠키 구성

Set-Cookie: rememberId=hong; Path=/; Domain=.example.com; Max-Age=2592000; Secure; HttpOnly; SameSite=Lax
속성 설명
name=value 쿠키 이름과 값
Path 이 경로 아래에서만 전송
Domain 이 도메인에서만 전송
Max-Age 초 단위 유효기간. 없으면 브라우저 종료 시 삭제(세션 쿠키)
Secure HTTPS에서만 전송
HttpOnly JavaScript로 접근 차단 (XSS 완화)
SameSite 크로스사이트 전송 제어 (Lax/Strict/None)

코드 예제 (서블릿)

// 쿠키 생성 (로그인 시 "아이디 기억하기")
Cookie remember = new Cookie("rememberId",
        URLEncoder.encode(userId, StandardCharsets.UTF_8));
remember.setPath("/");
remember.setMaxAge(60 * 60 * 24 * 30); // 30일
remember.setHttpOnly(true);
remember.setSecure(true);
resp.addCookie(remember);
// 쿠키 읽기
Cookie[] cookies = req.getCookies();
if (cookies != null) {
    for (Cookie c : cookies) {
        if ("rememberId".equals(c.getName())) {
            String id = URLDecoder.decode(c.getValue(), StandardCharsets.UTF_8);
            // 아이디 기억하기 처리
        }
    }
}

2. 세션(Session) — 서버가 기억하는 사용자 상태

개념

서버가 사용자별로 데이터를 저장하고, 식별용 ID(JSESSIONID)만 쿠키로 브라우저에 건네는 방식이다. 민감한 정보(로그인 상태, 권한)는 서버에만 있고, 브라우저에는 열쇠(세션 ID)만 있다.

동작 흐름

1. 브라우저 → 서버: 로그인 요청 (id/pw)
2. 서버: 인증 성공 → HttpSession에 사용자 정보 저장
3. 서버 → 브라우저: Set-Cookie: JSESSIONID=abc123
4. 이후 요청: 브라우저가 JSESSIONID 전송 → 서버가 해당 세션 찾아서 사용자 식별
5. 로그아웃: session.invalidate() → 세션 파기

코드 예제 (서블릿)

// 로그인 성공 시 세션 생성
HttpSession session = req.getSession();
session.setAttribute("loginUser", user);
session.setMaxInactiveInterval(30 * 60); // 30분 유휴 시 만료

// 세션 고정 공격 방지: 인증 후 세션 재발급
session.invalidate();
HttpSession newSession = req.getSession(true);
newSession.setAttribute("loginUser", user);
// 로그아웃
HttpSession session = req.getSession(false);
if (session != null) {
    session.invalidate();
}
resp.sendRedirect("/");

세션의 한계

  • 서버 메모리 사용: 동시 접속자가 많으면 메모리 부담
  • Scale-out 어려움: 서버를 여러 대로 늘리면 세션 공유가 필요
    • 해결책 1: 스티키 세션 — 같은 사용자를 같은 서버로 라우팅
    • 해결책 2: 외부 세션 저장소 — Redis 같은 공유 저장소에 세션 보관

3. 토큰(JWT) — 서버가 안 기억해도 되는 인증

개념

JWT(JSON Web Token)는 사용자 인증 정보를 토큰 자체에 담아서 클라이언트에게 건네는 방식이다. 서버가 세션을 저장할 필요가 없어서(Stateless) 확장성이 좋다.

JWT 구조

xxxxx.yyyyy.zzzzz
  │       │       │
Header  Payload  Signature
부분 내용
Header 알고리즘(HS256 등), 토큰 타입(JWT)
Payload 사용자 ID, 권한, 만료 시간 등 (클레임)
Signature Header + Payload + 서버 비밀키로 생성한 서명

동작 흐름

1. 브라우저 → 서버: 로그인 요청 (id/pw)
2. 서버: 인증 성공 → JWT 생성 → 클라이언트에 전달
3. 브라우저: JWT를 localStorage 또는 Cookie에 저장
4. 이후 요청: Authorization: Bearer <JWT> 헤더로 전송
5. 서버: JWT 서명 검증 → Payload에서 사용자 정보 추출

토큰의 장단점

장점 단점
서버가 상태를 안 저장 (Stateless) 토큰 탈취 시 만료까지 유효
서버 확장(Scale-out)에 유리 토큰 크기가 세션 ID보다 큼
마이크로서비스 간 인증 전달 쉬움 서버에서 강제 로그아웃 어려움
모바일 앱과 SPA에 적합 Payload는 Base64 인코딩일 뿐 암호화 아님

Access Token + Refresh Token 전략

실무에서는 토큰 탈취 위험을 줄이기 위해 두 종류의 토큰을 함께 사용한다.

토큰 용도 유효기간 저장 위치
Access Token API 인증 짧게 (15분~1시간) 메모리 또는 Cookie
Refresh Token Access Token 재발급 길게 (7일~30일) HttpOnly Cookie
1. Access Token 만료됨
2. 브라우저 → 서버: Refresh Token으로 재발급 요청
3. 서버: Refresh Token 검증 → 새 Access Token 발급
4. 브라우저: 새 Access Token으로 API 요청 계속

보안 체크리스트

쿠키 보안

  • HttpOnly 설정 — JavaScript 접근 차단 (XSS 완화)
  • Secure 설정 — HTTPS에서만 전송
  • SameSite=Lax 또는 Strict — CSRF 완화
  • 민감 정보(비밀번호, 토큰) 직접 저장 금지

세션 보안

  • 로그인 성공 시 세션 ID 재발급 — 세션 고정 공격 방지
  • 세션 만료 시간 적절히 설정 (보통 30분)
  • 분산 환경에서 세션 저장소 보안 확보

토큰 보안

  • Payload에 민감 정보 넣지 않기 (Base64 디코딩 가능)
  • Access Token 유효기간 짧게 설정
  • Refresh Token은 HttpOnly 쿠키에 저장
  • HTTPS 필수

실무에서 언제 뭘 쓸까?

상황 추천 방식 이유
전통적인 웹 서비스 (SSR) 세션 + 쿠키 서버 렌더링에 자연스러움
SPA (React, Vue 등) JWT API 기반 통신에 적합
모바일 앱 JWT 쿠키 관리가 어려운 환경
마이크로서비스 JWT 서비스 간 인증 전달 용이
"아이디 기억하기" 쿠키 단독 인증과 무관한 편의 기능
다크모드/언어 설정 쿠키 단독 사용자 설정 저장

마무리 체크리스트 (면접 대비)

  • 쿠키/세션/토큰의 저장 위치와 역할 차이를 10초 안에 설명할 수 있는가?
  • JSESSIONID가 무엇이고 어떤 역할을 하는지 아는가?
  • 세션 고정 공격이 무엇이고 어떻게 방지하는지 아는가?
  • JWT의 구조(Header/Payload/Signature)를 설명할 수 있는가?
  • Access Token + Refresh Token 전략을 설명할 수 있는가?
  • HttpOnly/Secure/SameSite 각각의 역할을 아는가?
  • 분산 환경에서 세션 유지 방법(스티키 세션 vs Redis)의 장단점을 아는가?
  • SPA에서 JWT를 쓰는 이유를 설명할 수 있는가?
728x90