[Backend] : Session? Cookie? Token?

Donghee Kim·2025년 10월 30일

문득문득

목록 보기
12/15
post-thumbnail

로그인을 할 때, 서버에서 로그인 중인지를 알기 위해서 대표적으로 Cookie, Session, Token 3가지 방식을 사용한다.

HTTPStateless(상태를 기억하지 않는) 프로토콜이기 때문이다.
=> 이는 각각의 요청서로 독립적이며 이전 요청과는 아무런 관련이 없다는 것을 의미!!

그러나 웹 애플리케이션은 사용자의 로그인 상태를 유지해야 한다.

이를 위해 Cookie, Session, Token과 같은 메커니즘이 사용된다.


로그인 인증을 위해서 CookieSession 은 같이 사용된다. 그렇기 때문에 CookieSession 은 세트메뉴이다.

Client(Browser)에 저장되는 데이터

  • 서버가 "이 사용자가 누구인지 기억해줘" 하고 작은 데이터를 브라우저에게 전달하면, 브라우저는 다음 요청마다 그 쿠키를 서버에 자동으로 보낸다.
  • 보통 로그인 상태 유지, 자동 로그인, 다크모드 설정 등에 사용된다.

Session

Server에 저장되는 사용자 정보

  1. 사용자가 로그인하면?
  2. 서버는 세션을 생성하고,
  3. 그 세션의 고유 ID(세션 ID) 를 브라우저의 쿠키에 담아 보관합니다.
  4. 사용자가 다음 요청을 보낼 때,
    브라우저는 그 세션 ID 쿠키를 함께 전송하고
  5. 서버는 그 ID를 보고 “아, 이건 로그인한 사용자구나!” 하고 알아봅니다

1. 사용자가 로그인 요청

  1. 사용자가 브라우저에서 ID/PW 입력

  2. 브라우저가 HTTP POST 요청으로 서버에 전송

    POST /login
    Content-Type: application/x-www-form-urlencoded
    
    id=donghee&pwd=1234

2. 서버에서 인증 처리

  1. 서버가 DB에 ID/PW 확인

  2. 로그인 성공 시, 서버는 Session 생성

    • Random 값 + 현재시간 + 사용자 ID
    • SHA256 해시
    import secrets
     import hashlib
     import time
     
     def generate_session_id(user_id=None):
    	~~~
        return session_id

    => 해당 방식을 통해, Session ID 생성

  3. 세션 데이터를 서버 저장소에 저장

    • Redis, DB, Memory

3. 서버가 세션 ID를 쿠키로 브라우저에 전달

서버는 HTTP 응답 헤더에 Set-Cookie를 포함한다.

HTTP/1.1 200 OK
Set-Cookie: session=abc123xyz789; HttpOnly; Path=/;

브라우저는 Cookie를 저장

  • Cookie 이름: session
  • Cookie 값: abc123xyz789 (세션 ID, 서버에서 세션 데이터와 연결)

4. 브라우저가 다음 요청 시 쿠키 전송

이제 사용자가 다른 페이지로 이동하면 브라우저는 자동으로 쿠키를 전송합니다.

GET /mypage
Cookie: session=abc123xyz789

서버는 이제 이 Session ID를 보고 서버 Session 저장소에서 사용자 정보를 찾아낸다.

5. 서버가 요청 처리 후 응답

  • 서버는 요청을 처리하고 사용자 정보를 기반으로 페이지를 렌더링
  • 브라우저는 여전히 세션 쿠키를 가지고 있음 → 로그인 상태 유지

6. 로그아웃 시

  1. 브라우저에서 로그아웃 요청

  2. 서버는 세션 삭제 또는 무효화

  3. 브라우저 쿠키 만료

Set-Cookie: session=; Max-Age=0

(쿠키 방식)만약 세션이 없다면?

from flask import Flask, make_response

@app.route("/set_cookie")
def set_cookie():
    resp = make_response("쿠키 저장 완료!")
    resp.set_cookie("username", "donghee", max_age=60)  # 60초 유지
    return resp
  1. 데이터(donghee)가 그대로 브라우저 쿠키에 저장됩니다.

  2. 브라우저는 쿠키를 요청마다 서버로 전송합니다:

Cookie: username=donghee

=> 서버가 별도로 세션을 만들 필요 없음

  • 장점: 단순, 서버 저장 공간 필요 없음

  • 단점: 브라우저에서 조작 가능, 보안 낮음

즉, 쿠키에 값 자체를 넣는 방식입니다.


  • 네이버 세션 확인하기

=> 해당 세션은 암호화되어 있어서 직접적인 세션 ID는 아니라고 함.


1) 보안 문제 : Session ID 탈취 위험

  • 공격자가 Session ID를 탈취하면?
    => Server는 그 사용자를 정상 사용자로 인식한다.

  • 탈취 Session을 무효화하려면?
    => Server에서 Session Storage를 전부 초기화해야 한다.

  • 문제점 : 정상 사용자까지 모두 재로그인해야 한다는 점이다.

2) HTTP Stateless 특성 위반

  • HTTP는 원래 stateless이다.
    즉, 서버는 클라이언트의 상태를 기억하지 않아야 한다.
  • 문제점 : 세션 기반 인증은 상태(로그인 정보)를 서버의 세션 저장소에 보관한다.

=> 결과적으로, 서버가 stateful 해진다.

3) 확장성 문제

  • 예를 들어, 2대의 Server(A, B)가 있다고 가정하자.
    사용자가 A 서버에 로그인하면? -> A 서버의 메모리에 세션 저장
    그런데 다음 요청을 B 서버가 처리하면 B 서버는 세션을 모르기 때문에 -> "로그인 안 됨" 상태가 됨.

해결법

  • 세션 클러스터링

    여러 서버가 세션을 서로 공유하도록 하는 방법입니다.
    세션 클러스터링에는 방법이 여러 가지다.

  • 스티키 세션

    같은 사용자의 요청은 항상 같은 서버로 보내는 방식.

  • 세션 스토리지 분리

    세션을 외부의 DB나 인메모리 저장소에 따로 저장.
    세션을 저장할 때는 대표적인 Key-Value DB인 Redis와 Memcached 를 사용


Token? JWT?

원래는 JWT / Token 은 들어봤다만... 이번에 업무 관련으로 코드 분석하다보니 CookieSession을 친구에게 물어보다보니

Session은 올드하다는 이런 사연으로 인해 JWTToken 을 공부하고자 한다.

Token 기반 인증이 등장한 이유?

해당 Session + Cookie의 문제점과 한계로 인해 등장했다.
서버가 상태를 저장하지 않고 stateless하게 인증 가능.

  • 토큰 자체에 사용자 정보(Claim)와 유효기간, 권한 정보가 들어있어
    → 서버는 토큰만으로 누구인지 확인 가능.

  • 여러 서버, MSA, 모바일/SPA 환경에서도 동일한 방식으로 인증 처리 가능.

  • 세션 공유, 클러스터링, sticky session 같은 복잡한 인프라를 피할 수 있음.

  • 탈취 시 토큰 만료 시간으로 제한 가능, 서버 재설정 불필요.

Token?

토큰(Token)은 말 그대로 인증을 위한 표식이다.
서버가 "이 사용자는 인증된 사용자" 라고 증명하기 위해 클라이언트에게 발급해주는 임시 열쇠이다.

  1. 사용자가 로그인하면?
    → 서버가 로그인 정보 확인 후 “토큰”을 발급합니다.

  2. 이후 사용자는 요청할 때마다
    → 이 “토큰”을 HTTP 헤더에 포함시켜 보냅니다.

  3. 서버는 토큰만 보고도 “누군지” 알 수 있습니다.

ex)

8f2b9af9c4f8413d91a15d0f6aabfcd0

일반적인 Token의 문제

토큰은 단순히 문자열일 뿐입니다.

서버가 “이 토큰은 user_id=123의 로그인 인증용”이라고 내부적으로 알고 있으면, 이 문자열만으로 인증이 가능합니다.

하지만 이런 임의 문자열 기반의 토큰에는 한계가 있습니다.

  • 보안 취약 토큰이 탈취되면 누가 사용 중인지 서버는 구분 불가
  • 저장소 필요 여전히 서버에서 “이 토큰이 유효한지” 확인해야 함 → 세션처럼 stateful
  • 확장성 부족 여러 서버가 있을 경우, 중앙에서 토큰 관리 필요

결국 기존의 단순한 “문자열 토큰” 방식도 서버 상태에 의존하거나, 관리 포인트가 늘어난다는 문제가 있었어요.

그래서 등장한 것이 JWT (JSON Web Token) “토큰 안에 인증 정보를 직접 담자!”
→ 서버에 따로 저장하지 않고도 인증이 가능하게 하자.

JWT(JSON Web Token)?

사용자의 인증 정보(예: user_id, 권한, 만료시간 등)를 JSON 형식으로 인코딩한 토큰입니다.

즉, 토큰 안에 누군지 / 언제까지 유효한지 / 어떤 권한을 가졌는지 모든 정보가 들어 있습니다.

이 덕분에 서버는 별도 저장소 없이, JWT의 서명(Signature)만 검증하면 사용자를 신뢰할 수 있습니다.

JWT 구조

xxxxx.yyyyy.zzzzz
  • xxxxx : Header
    토큰의 타입(JWT) 과 서명 알고리즘(HS256 등)

  • yyyyy : Payload
    실제 데이터 (user_id, exp, role)

  • zzzzz : Signature
    위 두 부분을 비밀키로 서명한 값 (변조 방지용)

  • JWT : JWT는 Base64로 인코딩된 문자열 형태입니다.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOjEyMywicm9sZSI6InVzZXIiLCJleHAiOjE3MzAyMjgwMDB9.
ZqS8ChSgq5hM-5VuPZTzoB8JzKAjlHn4hC9pY0-3m1Q
  • JWT를 디코딩하면 다음과 같은 JSON 정보가 나옴.

    • Header : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    {
      "alg": "HS256",
      "typ": "JWT"
     }
    • Payload : eyJ1c2VyIjoiZG9uZ2hlZSIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTczMDQ5NjAwMH0
    {
      "user": "donghee",
      "role": "admin",
      "exp": 1730496000
     }
    • Signature : ZqS8ChSgq5hM-5VuPZTzoB8JzKAjlHn4hC9pY0-3m1Q
      HMACSHA256(
        base64UrlEncode(header) + "." + base64UrlEncode(payload),
        secret_key
      )
Header.Payload.Signature

동작 방식 요약

  1. 클라이언트가 로그인 → 서버가 JWT 발급

  2. 이후 요청마다 JWTHTTP HEADER에 포함 (Authorization: Bearer <JWT>)
    Bearer Token : 클라이언트가 특정 리소스에 접근할 수 있는 권한을 증명하기 위해 서버에 전달하는 토큰

  3. 서버는 저장소 조회 없이 JWTSignature만 검증
    → 유효하면 요청 처리


Code Level 에서 JWT 로그인 만들기

간단하게 ChatGpt 로 구현해보았다.

  • 결과

로그인 창

js로 jwtlocal storage로 저장하게 했지만 아직 없는 것을 확인할 수 있다.

로그인 후, local storage에 jwt가 있는 것을 확인 가능하다.

토큰 허용 시간 설정

다음과 같이 설정

로그인 하자마자 Token으로 데이터 요청

해당 코드 처럼 decode가 되어 user를 뽑아서 "Welcome, admin!" 이 출력된 것을 볼 수 있다.

1분 후, 다시 만료된 Token으로 데이터 요청

=> 다음과 같이 정상적인 데이터와 비정상적인 데이터가 따로 조회되는 것을 확인 가능!

예제 코드

url : https://github.com/donghee-kim775/JWT_Practice

profile
WannaB.E/D.E

1개의 댓글

comment-user-thumbnail
2025년 11월 12일

https://token.dev/
JWT 검증 사이트인데 해당 사이트 이용하면 JWT 구조 이해에 더 도움될듯해요.

답글 달기