
최근 프로젝트에서 인증 관련 코드를 확인하다가, 토큰과 세션에 대해 다시 한번 공부하게 되었다. 예전에 블로그에 토큰 관련 내용을 정리한 적이 있지만 시간이 많이지나서 다시 정리해보려한다.

토큰과 세션의 가장 큰 차이
토큰과 세션의 핵심적인 차이는 데이터를 서버에 저장하느냐, 저장하지 않느냐이다.
- 세션(Session) 은 사용자의 상태를 서버 측 저장소(메모리, DB, Redis 등)에 저장한다.
- 토큰(Token) 은 사용자 정보를 자체적으로 담고 있으며, 서버는 해당 토큰을 검증하기만 한다.
물론 토큰 방식도 고도화 과정에서 서버에 데이터를 저장하는 경우가 생긴다.
JWT 토큰이란?
JWT(Json Web Token)는 인증 정보를 안전하게 전달하기 위해 JSON 기반으로 인코딩된 토큰이다.
구조는 Header.Payload.Signature 세 부분으로 나뉘며, Payload 에 사용자 정보(클레임)가 들어있고, Signature 로 변조 여부를 확인할 수 있다.
세션이란?
세션은 클라이언트가 로그인하면 서버가 고유한 세션 ID를 발급하고, 그 ID에 해당하는 사용자 정보를 서버 측 세션 저장소에 보관한다. 클라이언트는 이후 요청마다 세션 ID를 쿠키에 담아 서버로 보내고, 서버는 세션 저장소를 조회해 인증을 확인한다.
토큰 vs 세션, 단순 비교
- 세션: 서버에 상태를 저장. 확실하고 직관적이지만 다중 서버 환경에서는 세션 동기화(세션 클러스터링, Redis 등)가 필요하다.
- 토큰: 서버는 상태를 저장하지 않아도 되므로 확장성이 좋다. 하지만 로그아웃, 중복 로그인 제어, 토큰 무효화 등 기능을 구현하려면 결국 서버 저장소를 사용해야 한다.
토큰의 장단점
장점
- 서버가 상태를 저장하지 않아도 되므로 확장성이 좋다. 서버 증설/축소에도 영향을 받지 않는다.
- 서버 간 공유 저장소가 필요 없어 MSA 환경에 친화적이다.
단점
- 로그아웃, 중복 로그인 제어 등 무상태 특성 때문에 제어가 어렵다.
- 토큰은 만료되기 전까지는 계속 유효하기 때문에, 로그아웃 직후에도 사용할 수 있다. → 해결하려면 블랙리스트/화이트리스트 방식, Refresh Token 관리 등 서버 저장소를 도입해야 한다.
- Payload 노출 위험이 있으므로 민감 정보는 넣을 수 없다.
세션의 장단점
장점
- 서버에서 직접 상태를 관리하기 때문에 보안성이 높다. 로그아웃 즉시 세션 무효화가 가능하다.
- 구현이 직관적이고 단순하다.
단점
- 스케일 아웃 문제: 서버가 여러 대라면, 특정 사용자의 세션이 A 서버에 저장되어 있을 때 B 서버가 요청을 받으면 인증이 실패한다.
- 스티키 세션(Sticky Session): 같은 사용자의 요청을 항상 같은 서버로 보내는 방식. 하지만 특정 서버에 부하가 몰리고, 장애 시 위험하다.
- 외부 저장소(Redis, DB 등): 모든 서버가 세션을 공유할 수 있지만, 단일 저장소가 SPOF(Single Point of Failure) 가 될 수 있다.
- 이를 방지하기 위해 Redis Sentinel, Cluster, 다중 AZ 배포 등 고가용성 구성을 고려해야 한다.
토큰 방식의 고민들
1. 로그아웃
토큰은 서버가 별도로 관리하지 않기 때문에, 사용자가 로그아웃하더라도 토큰 자체는 만료 전까지 여전히 유효하다.
이를 보완하기 위해:
- Access Token 은 짧게 설정한다.
- Refresh Token 은 길게 유지하며 필요시 새로운 Access Token을 발급한다.→ 이를 해결하려면 토큰 블랙리스트를 서버에서 관리해야 한다.
- 그러나 이 방식만으로는 로그아웃 직후에도 Access Token이 살아있는 문제가 발생한다.
2. 중복 로그인 방지
JWT 기반 시스템에서 한 계정으로 여러 기기에서 동시에 로그인하는 것을 막으려면 서버 측 저장소에 현재 사용 중인 토큰 정보를 저장해야 한다. 즉, 토큰 기반 인증이라도 결국 세션과 유사한 구조가 된다.
3. 블랙리스트와 화이트리스트
- 블랙리스트: 만료되지 않았지만 더 이상 유효하지 않은 토큰(로그아웃된 토큰 등)을 서버에 기록하고, 요청 시 검증한다.
- 화이트리스트: 서버에 현재 유효한 토큰만 기록해 두고, 리스트에 없는 토큰은 무효 처리한다.
이런 관리 방식은 필연적으로 서버 저장소를 사용해야 한다.
정리
토큰은 "무상태(stateless)"라는 장점으로 확장성과 속도에서 유리하다. 하지만 로그아웃, 중복 로그인 방지, 토큰 무효화와 같은 기능을 구현하려다 보면 결국 서버 저장소를 도입해야 하고, 오히려 세션보다 복잡해진다.
세션은 다중 서버 환경에서 동기화 문제가 있지만, 보안성과 직관성 면에서는 단순하고 확실하다.
결국 중요한 것은 상황에 맞는 선택이다. 보안이 더 중요한 서비스인지, 확장성이 더 중요한 서비스인지에 따라 세션과 토큰 중 적절한 방식을 선택하는 것이 바람직하다.
'Java , Spring > Java' 카테고리의 다른 글
| [Java] HashMap의 Thread-Safe 와 TreeMap, LinkedHashMap, EntrySet 정리 (0) | 2024.10.07 |
|---|---|
| [JAVA] Virtual Thread (JDK 21) (1) | 2024.09.03 |
| [Java] CS 스터디 - 2주차 (Java & Spring) (0) | 2024.08.11 |
| [Java] CS 스터디 - 1주차 (Java & Spring) (0) | 2024.08.02 |
| [Java] UncheckedException과 CheckedException (Error와 Exception) (0) | 2024.01.22 |
댓글