쿠키 vs 세션
HTTP는 무상태(Stateless) 프로토콜. 로그인 상태를 유지하려면 별도 메커니즘이 필요하다.
동작 원리 비교
[쿠키 방식]
Client Server
|-- 로그인 ------→|
|←- Set-Cookie ---| user=kim
|-- 요청 --------→| Cookie: user=kim
| (매 요청마다 쿠키 포함)
[세션 방식]
Client Server
|-- 로그인 ------→|
|←- Set-Cookie ---| sid=abc123
|-- 요청 --------→| Cookie: sid=abc123
| Server: sessions[abc123]
| → {user: kim, role: admin}
핵심 차이
| 구분 | 쿠키 | 세션 |
|---|
| 저장 위치 | 클라이언트 (브라우저) | 서버 (메모리/DB) |
| 보안 | 취약 (조작 가능) | 상대적 안전 |
| 크기 | 4KB 제한 | 서버 메모리 한도 |
| 서버 부하 | 없음 | 세션 저장소 필요 |
| 확장성 | 좋음 | Sticky Session 필요 |
| 만료 | Expires/Max-Age | 서버에서 관리 |
세션의 확장성 문제
[서버 1대] → 세션 메모리에 저장 → OK
[서버 여러 대]
Client → LB → Server A (세션 있음)
Client → LB → Server B (세션 없음)
해결 방법:
1. Sticky Session (같은 서버로)
2. 세션 공유 저장소 (Redis)
3. JWT (서버에 저장 안 함)
JWT의 등장
[JWT 방식]
Client Server
|-- 로그인 ------→|
|←- JWT 토큰 -----| (서명된 토큰)
|-- 요청 --------→| Authorization:
| | Bearer eyJhbG...
| 서버: 토큰 서명 검증만
| (저장소 불필요!)
| 구분 | 세션 | JWT |
|---|
| 서버 저장 | 필요 (Redis 등) | 불필요 |
| 무효화 | 세션 삭제 | 어려움 (만료 대기) |
| 확장성 | 세션 공유 필요 | 뛰어남 |
| 페이로드 | 서버에 저장 | 토큰에 포함 |
실무 선택 가이드
| 상황 | 추천 |
|---|
| 단일 서버, 전통 웹 | 세션 + 쿠키 |
| 다중 서버, MSA | JWT |
| 모바일 앱 API | JWT |
| 즉시 로그아웃 필수 | 세션 (또는 JWT + 블랙리스트) |
| SSR (Next.js 등) | 세션 또는 JWT + httpOnly 쿠키 |
보안 고려사항
| 위협 | 대응 |
|---|
| XSS로 토큰 탈취 | httpOnly 쿠키 사용 |
| CSRF 공격 | SameSite 속성, CSRF 토큰 |
| 세션 하이재킹 | HTTPS 필수, Secure 플래그 |
| JWT 탈취 | 짧은 만료 + Refresh Token |
Q.쿠키와 세션의 차이를 설명해주세요.
상태를 어디에 두는지가 다릅니다.
| 항목 | 쿠키 | 세션 |
|---|
| 저장 위치 | 클라이언트 | 서버 |
| 클라이언트가 갖는 것 | 값 자체 | 식별자만 |
| 위변조 | 가능하다. 서명이 필요 | 어렵다. 값은 서버에 있다 |
| 용량 | 4KB 안팎 | 서버 메모리나 저장소만큼 |
| 확장 | 서버 수와 무관 | 서버 간 공유가 필요 |
쿠키는 전달 수단이고 세션은 저장 방식이라 대립 개념이 아닙니다. 세션도 보통 쿠키로 식별자를 실어 나릅니다.
민감한 값을 쿠키에 직접 담으면 사용자가 바꿀 수 있으므로, 담아야 한다면 서명하거나 암호화합니다.
흔한 실수: 쿠키가 세션보다 안전하지 않다고 단정하는 것. httpOnly, Secure, SameSite 를 걸면 상당히 안전해지고, 세션도 식별자가 탈취되면 그대로 뚫립니다.
Q.세션 방식의 확장성 문제는 어떻게 해결하나요?
서버가 여러 대면 어느 서버가 그 세션을 갖고 있느냐가 문제가 됩니다.
| 방법 | 내용 | 대가 |
|---|
| 고정 세션 | 같은 사용자를 같은 서버로 보낸다 | 그 서버가 죽으면 세션이 사라진다. 부하가 고르지 않다 |
| 세션 복제 | 모든 서버가 서로 복사한다 | 서버가 늘수록 복제 비용이 폭증한다 |
| 외부 저장소 | Redis 같은 공용 저장소에 둔다 | 조회 왕복이 붙는다. 저장소가 단일 장애점이 된다 |
| 무상태 토큰 | 서버가 저장하지 않는다 | 즉시 무효화가 어려워진다 |
실무에서는 외부 저장소가 가장 흔합니다. 왕복 1ms 안팎이면 감당할 만하고, 서버를 자유롭게 늘리고 줄일 수 있습니다.
흔한 실수: 고정 세션을 기본 해법으로 답하는 것. 배포할 때마다 사용자가 로그아웃되고, 오토스케일링과 잘 맞지 않습니다.
Q.JWT의 장점과 단점을 설명해주세요.
| 장점 | 단점 |
|---|
| 서버가 저장하지 않아 수평 확장이 쉽다 | 만료 전 무효화가 어렵다 |
| 검증에 DB 조회가 없다 | 페이로드가 커져 매 요청 크기가 늘어난다 |
| 서비스 간 전달이 쉽다 | 내용이 누구에게나 보인다. 서명은 위조만 막는다 |
| 클레임에 권한을 담을 수 있다 | 권한이 바뀌어도 옛 토큰이 유효하다 |
무효화가 어려운 이유는 서버가 발급 사실을 기억하지 않기 때문입니다. 그래서 실무에서는 수명을 짧게(15분 안팎) 두고 갱신 토큰으로 보완하거나, 차단 목록을 두어 무상태를 일부 포기합니다.
흔한 실수: JWT 를 세션의 상위 호환으로 답하는 것. 트래픽이 한 서버로 충분하고 즉시 로그아웃이 중요하다면 세션이 더 단순하고 안전합니다.
Q.XSS와 CSRF 공격에 대해 쿠키/세션을 어떻게 보호하나요?
| 공격 | 막는 방법 |
|---|
| XSS 로 쿠키 탈취 | httpOnly 로 스크립트 접근을 막는다 |
| 중간에서 가로채기 | Secure 로 HTTPS 에서만 전송한다 |
| CSRF | SameSite 로 다른 사이트 요청에 쿠키를 싣지 않는다 |
| CSRF (보완) | 요청마다 검증 토큰을 요구한다 |
| 세션 고정 | 로그인 성공 시 세션 식별자를 새로 발급한다 |
| 탈취 후 장기 사용 | 만료를 두고, 민감 동작에 재인증을 요구한다 |
순서가 중요합니다. XSS 를 먼저 막습니다. 스크립트를 실행할 수 있으면 CSRF 토큰을 읽어 정상 요청을 만들 수 있어 CSRF 방어가 무력화됩니다.
흔한 실수: httpOnly 만 걸고 끝내는 것. 쿠키를 못 읽어도 XSS 가 있으면 그 페이지에서 직접 요청을 보낼 수 있습니다. 출력 이스케이프가 여전히 1차 방어입니다.
Q.세션 기반 vs 토큰 기반 인증, 언제 뭘 쓰나요?
즉시 무효화가 중요한지, 확장과 서비스 간 전달이 중요한지로 갈립니다.
| 조건 | 고를 것 |
|---|
| 로그아웃과 계정 정지가 즉시 반영돼야 한다 | 세션 |
| 서버가 여러 대이고 상태를 공유하기 싫다 | 토큰 |
| 여러 서비스가 같은 인증을 쓴다 | 토큰 |
| 모바일 앱과 서드파티 클라이언트 | 토큰 |
| 단일 웹 서비스이고 단순함이 중요하다 | 세션 |
실무에서는 섞어 씁니다. 액세스 토큰은 짧게 두어 무상태의 이점을 얻고, 갱신 토큰은 서버가 관리해 무효화 수단을 남깁니다.
흔한 실수: 토큰이 최신 방식이라 항상 낫다고 답하는 것. 세션은 저장소 왕복 1ms 로 즉시 무효화를 얻습니다. 무엇을 포기할지 정하는 문제입니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
네트워크 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.