쿠키 세션 차이 — 쿠키는 그대로인데 왜 로그아웃될까

@JavaPark · 2026년 11월 12일 · 12 min read

쿠키 세션 차이 커버 — 세션 쿠키 36B, 정보를 쿠키에 담으면 167B, 쿠키 4,096B 저장 4,097B 버림, 서버 재시작 후 401
쿠키 세션 차이 커버 — 세션 쿠키 36B, 정보를 쿠키에 담으면 167B, 쿠키 4,096B 저장 4,097B 버림, 서버 재시작 후 401

안녕하세요, 자바파커입니다.

"쿠키는 클라이언트에 저장하고, 세션은 서버에 저장한다."

면접 준비할 때 다들 이 한 줄로 외우셨을 겁니다. 틀린 말은 아닌데, 이 한 줄로는 설명이 안 되는 장면이 있습니다.

서버를 재시작했더니 사용자가 전부 로그아웃됐습니다. 그런데 브라우저를 열어 보면 쿠키는 그대로 있습니다. 쿠키가 남아 있는데 왜 로그인이 풀렸을까요?

결론부터 말씀드리면, 쿠키는 손님이 들고 다니는 번호표이고, 세션은 서버가 들고 있는 장부입니다. 로그인 정보는 번호표가 아니라 장부에 있습니다. 장부가 비면, 번호표를 아무리 내밀어도 "누구세요?"가 됩니다.

말로만 하면 감이 안 와서, 제 PC에서 작은 서버와 크롬(Chromium 151)으로 직접 재 봤습니다. 이 장면은 영상으로도 정리했습니다.

쿠키 세션 차이 영상 — 아라 사장님이 401 도장 앞에서 놀라는 장면, 상단 띠 '쿠키는 번호표, 세션은 서버 장부'
쿠키 세션 차이 영상 — 아라 사장님이 401 도장 앞에서 놀라는 장면, 상단 띠 '쿠키는 번호표, 세션은 서버 장부'


쿠키 세션 차이 한눈에 보기

쿠키 세션
어디에 있나 브라우저 서버(메모리, Redis, DB 등)
무엇이 들어 있나 이름=값 한 쌍 (보통 세션 ID 하나) 사용자 정보, 장바구니 등 실제 상태
언제 오가나 요청마다 자동으로 서버에 따라간다 오가지 않는다. 서버 안에 있다
크기 쿠키 하나에 약 4KB까지 (실측: 4,096바이트) 서버 저장소 용량만큼
누가 볼 수 있나 브라우저 사용자 (HttpOnly 가 아니면 자바스크립트도) 서버만
비유 손님이 들고 있는 진동벨 번호표 카운터의 주문 장부

둘은 서로 대체하는 관계가 아닙니다. 세션 방식은 쿠키를 써서 동작합니다. 쿠키에는 번호만 넣고, 그 번호로 서버의 장부를 찾습니다.

직접 재 봤습니다

실험 방법

Node 기본 http 모듈로 작은 서버를 띄우고, Playwright로 실제 크롬을 띄워 로그인부터 재시작까지 했습니다. 외부 네트워크 없이 127.0.0.1에서만 돌았고, 3회 모두 결과가 같았습니다.

// 세션 방식: 쿠키엔 번호만, 정보는 서버 메모리(장부)에
if (req.url === "/login-session") {
  const sid = crypto.randomBytes(16).toString("hex")
  sessions.set(sid, user) // 장부에 적기
  res.setHeader("Set-Cookie", `sid=${sid}; Path=/; HttpOnly`)
}
// 쿠키에 다 담기: 사용자 정보를 통째로 쿠키에
if (req.url === "/login-cookie") {
  res.setHeader(
    "Set-Cookie",
    `user=${Buffer.from(JSON.stringify(user)).toString("base64url")}; Path=/`
  )
}
// 내 정보: 장부에 번호가 있으면 200, 없으면 401
if (req.url === "/me") {
  res.statusCode = sessions.get(cookies.sid) ? 200 : 401
}

사용자 정보는 { id, name, role, cart(3개), theme, lang } 6개 필드짜리 작은 객체입니다.

결과

측정 결과
세션 방식 쿠키 sid=… 36바이트, HttpOnly
사용자 정보를 쿠키에 담은 user=… 167바이트, HttpOnly 아님
쿠키 하나(이름+값) 4,096바이트 저장됨
쿠키 하나(이름+값) 4,097바이트 오류 없이 버려짐
서버 재시작 뒤 브라우저 쿠키 그대로 있음 (같은 sid)
서버 재시작 뒤 /me 401

쿠키는 그대로인데 왜 401일까 — 장부가 비었다

이 실험의 서버는 세션을 메모리의 Map 에 저장했습니다. 프로세스가 재시작되면 메모리는 새로 시작하니, 장부가 빈 공책이 됩니다.

브라우저는 그런 사정을 모릅니다. 들고 있던 sid=03c8… 쿠키를 그대로 보냅니다. 서버는 장부에서 그 번호를 찾지 못하니 "누구세요?", 즉 401 Unauthorized 를 돌려줍니다.

같은 일이 서버를 여러 대로 늘렸을 때도 생깁니다. 로그인은 1번 서버 장부에 적혔는데, 다음 요청이 2번 서버로 가면 거기 장부엔 그 번호가 없습니다.

그래서 실무에서는 세션을 서버 밖의 공용 저장소(Redis 같은)에 둡니다. Node의 express-session 문서도 기본 메모리 저장소(MemoryStore)는 운영 환경용으로 만들어지지 않았다고 분명히 적어 두었습니다.

그럼 정보를 쿠키에 다 담으면 안 되나

장부를 없애고 정보를 쿠키에 다 담으면 재시작 문제는 사라집니다. 대신 세 가지가 따라옵니다.

  1. 매 요청마다 통째로 간다. 실측에서 작은 객체 하나에 167바이트였습니다. 이미지·CSS·API 요청 모두에 이 바이트가 붙습니다.
  2. 누구나 열어 볼 수 있다. base64는 암호가 아니라 포장입니다. 개발자 도구에서 그대로 풀립니다. HttpOnly 를 안 붙이면 페이지의 자바스크립트도 읽습니다.
  3. 4KB 벽이 있다. 크롬은 이름+값이 4,096바이트를 넘는 쿠키를 오류 없이 버렸습니다. 정보가 조금씩 늘다가 어느 날 로그인이 안 되는 이유가 됩니다.

실무에서 "쿠키에 담는" 방식은 보통 서명된 쿠키나 JWT 입니다. 서명이 있으면 위조는 막을 수 있지만, 암호화하지 않는 한 내용은 여전히 읽힙니다. 그래서 비밀번호나 개인정보는 넣지 않습니다.

쿠키에 꼭 붙이는 속성 세 가지

세션 ID를 담는 쿠키라면 이 셋은 기본으로 붙입니다.

  • HttpOnly: 자바스크립트가 못 읽게 막습니다. XSS로 세션을 훔쳐 가는 것을 줄입니다.
  • Secure: HTTPS 에서만 보냅니다.
  • SameSite: 다른 사이트에서 온 요청에 쿠키를 붙일지 정합니다. CSRF를 줄입니다.

면접에서 쿠키 세션 차이를 답하는 법

한 줄 답변

"쿠키는 브라우저가 저장해 요청마다 자동으로 보내는 작은 데이터이고, 세션은 서버가 사용자 상태를 저장하는 방식입니다. 보통 쿠키에는 세션 ID만 넣고, 실제 정보는 서버의 세션 저장소에서 찾습니다."

꼬리 질문에 대비할 세 가지

  1. "서버를 재시작하면 왜 로그아웃되나요?" → 세션을 서버 메모리에 저장했기 때문입니다. 쿠키는 남아도 장부가 비어 그 ID를 모릅니다. Redis 같은 바깥 저장소로 해결합니다.
  2. "서버가 여러 대면요?" → 같은 문제입니다. 공용 세션 저장소를 쓰거나, 같은 사용자를 같은 서버로 보내는 스티키 세션을 씁니다.
  3. "JWT랑 세션은 뭐가 달라요?" → JWT는 정보를 토큰 자체에 담아 서버 저장소가 필요 없습니다. 대신 토큰이 커지고, 발급한 뒤에는 서버가 마음대로 무효화하기 어렵습니다.

자주 묻는 것

브라우저를 닫으면 쿠키도 사라지나요?

Expires나 Max-Age가 없는 쿠키는 브라우저를 닫으면 사라집니다(세션 쿠키). 둘 중 하나가 있으면 그 시간까지 남습니다.

쿠키 4KB는 모든 브라우저가 같나요?

RFC 6265는 브라우저가 쿠키 하나당 최소 4,096바이트를 지원하라고 권합니다. 이 글의 4,096/4,097 경계는 Chromium 151에서 직접 잰 값이고, 세부 규칙은 브라우저마다 다를 수 있습니다.

세션 ID 길이 36바이트는 표준인가요?

아닙니다. 이 실험에서 16바이트 난수를 hex로 쓴 결과입니다. 프레임워크마다 길이가 다르고, 서명이 붙으면 더 길어집니다. 중요한 건 길이가 아니라 추측할 수 없을 만큼 무작위인가입니다.


정리

  • 쿠키 = 들고 다니는 번호표, 세션 = 서버의 장부. 세션 방식은 쿠키에 번호만 넣는다.
  • 실측: 세션 쿠키 36바이트, 정보를 쿠키에 담으면 167바이트가 요청마다 따라감, 쿠키는 4,097바이트부터 버려짐.
  • 서버 재시작 뒤 쿠키는 그대로인데 401: 메모리 장부가 비었기 때문. 공용 저장소(Redis 등)로 해결.
  • 정보를 쿠키에 담을 땐 서명·크기·노출을 같이 생각한다.

HTTP 응답 코드를 이어서 보시려면 HTTP 상태 코드 정리(401 vs 403 포함)도 함께 읽어 보세요.

여러분 서비스는 세션을 어디에 저장하고 계신가요? 재시작했을 때 로그인이 풀렸던 경험이 있으면 댓글로 들려주세요.

참고 자료

퀴즈

서버를 재시작한 뒤 사용자들이 모두 로그아웃됐습니다. 브라우저의 세션 쿠키(sid)는 그대로 남아 있습니다. 가장 가능성 높은 원인은?

이 문제가 쉬웠다면 — 백엔드 CS 능력고사 20문제→
그림으로 말하는 백엔드 CS 20 무료 샘플 표지

판매 중 · 14,900원 · 무료 샘플 15쪽

그림으로 말하는 백엔드 CS 20

백엔드 CS 20문항을 면접에서 60초로 설명하는 연습. 샘플 5문항부터 받아 보세요.

→
@JavaPark
AI 시대의 개발자 도구, 실전 경험을 공유합니다