웹 애플리케이션에서 사용자를 식별하고 권한을 관리하는 건 정말 중요한데, 이걸 위해 쿠키, 세션, 토큰이라는 세 가지 방식이 주로 쓰인다. 각각 어떤 특징이 있고 언제 써야 하는지 알아보자.
1. 쿠키(Cookie)란?
쿠키는 서버가 사용자의 브라우저에 저장하는 작은 데이터 조각이다. 사용자가 웹사이트를 방문하면 서버는 쿠키를 생성해서 브라우저로 보내고, 브라우저는 이걸 저장해뒀다가 같은 서버에 요청할 때마다 자동으로 함께 보낸다.
쿠키의 주요 특징
- 클라이언트 저장: 사용자의 브라우저에 저장됨
- 자동 전송: 같은 도메인으로 요청할 때 자동으로 포함됨
- 만료 시간: 설정한 기간이 지나면 자동으로 삭제됨
- 용량 제한: 도메인당 약 4KB로 제한됨
- 도메인 제한: 특정 도메인에서만 접근 가능
쿠키의 장단점
장점:
- 구현이 간단함
- 서버의 부담이 적음
- 만료 시간을 설정해서 지속성 유지 가능
단점:
- 보안에 취약할 수 있음 (XSS 공격 위험)
- 용량 제한이 있음
- 매 요청마다 전송되어 네트워크 부담
2. 세션(Session)이란?
세션은 사용자 정보를 서버에 저장하는 방식이다. 사용자가 로그인하면 서버는 세션을 생성하고 고유한 세션 ID를 발급한다. 이 세션 ID는 쿠키를 통해 클라이언트로 전달되고, 클라이언트는 이후 요청 시 세션 ID를 보내서 자신을 식별한다.
세션의 동작 방식
- 사용자가 로그인 요청
- 서버가 사용자 정보 확인
- 서버가 세션 생성하고 세션 저장소에 저장
- 서버가 세션 ID를 쿠키로 클라이언트에 전달
- 클라이언트가 이후 요청마다 세션 ID 쿠키 전송
- 서버가 세션 ID로 세션 저장소에서 사용자 정보 조회
세션의 장단점
장점:
- 서버에서 사용자 정보를 관리해서 보안성이 높음
- 클라이언트는 세션 ID만 저장하면 됨
- 서버에서 세션을 제어할 수 있음 (강제 로그아웃 등)
- 저장할 수 있는 데이터 크기에 제한이 거의 없음
단점:
- 서버 메모리나 저장소 자원을 사용함
- 서버 확장 시 세션 동기화 문제
- 서버 부하가 증가할 수 있음
3. 토큰(Token)이란?
토큰은 사용자 인증 정보를 담은 암호화된 문자열이다. 주로 JWT(JSON Web Token)가 사용되는데, 서버가 토큰을 발급하면 클라이언트는 이걸 저장했다가 요청 시마다 헤더에 포함해서 보낸다.
JWT 구조
JWT는 점(.)으로 구분된 세 부분으로 이뤄진다:
- Header: 토큰 타입과 해싱 알고리즘 정보
- Payload: 실제 전달할 데이터 (클레임)
- Signature: 토큰 검증을 위한 서명
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NSIsInVzZXJuYW1lIjoiam9obiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
토큰의 동작 방식
- 사용자가 로그인 요청
- 서버가 사용자 정보 확인
- 서버가 JWT 생성 (사용자 정보 포함)
- 서버가 토큰을 클라이언트에 전달
- 클라이언트가 토큰 저장 (로컬 스토리지, 쿠키 등)
- 클라이언트가 요청 시 Authorization 헤더에 토큰 포함
- 서버가 토큰 검증 후 요청 처리
토큰의 장단점
장점:
- 서버가 상태를 저장하지 않아 확장성이 좋음 (Stateless)
- 여러 도메인에서 사용 가능 (CORS 문제 해결)
- 모바일 앱에서 사용하기 좋음
- 서버 부하가 적음
- 토큰 자체에 정보가 담겨 있어 DB 조회 불필요
단점:
- 토큰 크기가 세션 ID보다 큼
- 토큰이 탈취되면 만료 전까지 무효화하기 어려움
- 페이로드 정보는 암호화되지 않아 민감한 정보 저장 불가
- 토큰 갱신 로직 구현이 복잡할 수 있음
4. 세 가지 방식 비교
특성 쿠키 세션 토큰
| 저장 위치 | 클라이언트 | 서버 | 클라이언트 |
| 보안성 | 낮음 | 높음 | 중간 |
| 서버 부하 | 낮음 | 높음 | 낮음 |
| 확장성 | 높음 | 낮음 | 높음 |
| 용량 | ~4KB | 제한 없음 | 크기 유연 |
| 만료 관리 | 자동 | 서버 제어 | 토큰 자체 |
| 상태 저장 | Stateless | Stateful | Stateless |
5. Access Token과 Refresh Token
실제 서비스에선 보안과 사용자 경험을 동시에 고려해서 Access Token과 Refresh Token을 함께 쓰는 경우가 많다.
두 토큰의 역할
- Access Token: 실제 API 요청에 사용, 수명이 짧음 (15분~1시간)
- Refresh Token: Access Token 갱신에 사용, 수명이 김 (7일~30일)
동작 흐름
- 로그인 시 Access Token과 Refresh Token 발급
- API 요청 시 Access Token 사용
- Access Token 만료 시 Refresh Token으로 새 Access Token 발급
- Refresh Token도 만료되면 다시 로그인
6. 보안 고려사항
쿠키 보안
- HttpOnly 플래그: JavaScript로 쿠키 접근을 막아줌
- Secure 플래그: HTTPS에서만 전송되게 설정
- SameSite 속성: CSRF 공격을 방어함
- 쿠키 암호화: 중요한 정보는 암호화해서 저장
세션 보안
- 세션 ID 예측 불가능하게: 충분히 긴 랜덤 문자열 사용
- 세션 고정 공격 방어: 로그인할 때 세션 ID를 새로 생성
- 세션 타임아웃: 적절한 만료 시간 설정
- 안전한 세션 저장소: Redis 같은 보안이 강화된 저장소 사용
토큰 보안
- HTTPS 사용 필수: 토큰 전송할 때 암호화가 필수
- 짧은 만료 시간: Access Token은 가능한 짧게 설정
- Refresh Token 보호: HttpOnly 쿠키에 저장
- 민감 정보 제외: Payload에 비밀번호, 카드번호 같은 거 넣으면 안 됨
- 토큰 블랙리스트: 로그아웃할 때 토큰을 블랙리스트에 추가
- 강력한 비밀키: 충분히 복잡한 시크릿 키 사용
7. 어떤 방식을 선택해야 할까..?
세션 기반 인증을 선택하는 경우
- 서버 중심의 전통적인 웹 애플리케이션
- 단일 서버이거나 세션 공유가 쉬운 환경
- 실시간으로 세션을 무효화해야 하는 경우
- 높은 보안이 필요한 금융 서비스
토큰 기반 인증을 선택하는 경우
- RESTful API 서버
- 마이크로서비스 아키텍처
- 모바일 앱, SPA(Single Page Application)
- 서버 확장성이 중요한 대규모 서비스
- 여러 도메인에서 인증 정보를 공유해야 하는 경우
하이브리드 방식
많은 현대적인 애플리케이션은 두 방식의 장점을 섞어서 쓴다:
- Access Token은 클라이언트 메모리에 저장 (보안)
- Refresh Token은 HttpOnly 쿠키에 저장 (XSS 방어)
- 중요한 작업은 추가 인증 요구 (2FA 등)
8. 실전 팁과 베스트 프랙티스
토큰 저장 위치
- Local Storage: XSS에 취약함, 권장하지 않음
- Session Storage: 탭 닫으면 삭제됨, 일부 시나리오에서 유용
- 메모리: 가장 안전하지만 새로고침하면 로그아웃됨
- HttpOnly Cookie: Refresh Token 저장에 권장
실무 권장 구조
- 로그인할 때 Access Token(짧은 수명)과 Refresh Token(긴 수명) 발급
- Access Token은 메모리나 상태 관리 라이브러리에 저장
- Refresh Token은 HttpOnly 쿠키에 저장
- Access Token 만료되면 Refresh Token으로 자동 갱신
- Refresh Token 만료되면 다시 로그인 요구
성능 최적화
- 세션 쓸 때는 Redis 같은 In-memory DB 활용
- 토큰 페이로드 최소화
- 불필요한 인증 요청 캐싱
9. 결론
쿠키, 세션, 토큰은 각각 고유한 특징과 장단점이 있다. 요즘 웹 애플리케이션에서는 토큰 기반 인증이 점점 더 선호되고 있지만, 세션 기반 인증도 여전히 많은 상황에서 유효하다.
가장 중요한 건 자기 프로젝트 요구사항을 정확히 파악하고, 보안과 사용자 경험, 확장성 사이의 균형을 찾는 거다. 때로는 두 방식을 섞은 하이브리드 접근법이 최선의 선택일 수 있다.
어떤 방식을 선택하든 항상 보안을 최우선으로 고려하고, HTTPS 사용, 적절한 만료 시간 설정, XSS 및 CSRF 방어 같은 기본적인 보안 원칙을 지켜야 한다.
'Knowledge' 카테고리의 다른 글
| Response Body에 HTTP Status Code를 담아도 괜찮을까? (1) | 2025.12.13 |
|---|---|
| [CS 기초 시리즈 #2] DNS와 서버 그리고 클라우드 (1) | 2025.11.02 |
| [CS 기초 시리즈 #1] 개발에 들어가기 앞서.. (1) | 2025.11.02 |