JWT 세션 토큰 구현: 스테이트풀(Stateful) vs 스테이트리스(Stateless)
JSON Web Token(JWT)은 당사자 간에 정보를 JSON 객체로 안전하게 전송하기 위한 업계 표준이 되었습니다. 세션 관리에 있어 개발자들은 종종 중요한 아키텍처 결정을 내려야 합니다. 바로 구현 방식이 **스테이트리스(Stateless)**여야 하는지, 아니면 **스테이트풀(Stateful)**이어야 하는지입니다.
두 방식 모두 장단점이 있으며, 적절한 선택은 애플리케이션의 규모, 보안 요구 사항 및 인프라에 따라 달라집니다.
1. 스테이트리스(Stateless) JWT 구현
순수 스테이트리스 구현에서는 모든 세션 데이터(사용자 ID, 역할, 만료 시간)가 JWT 자체에 직접 저장됩니다. 서버는 데이터베이스나 캐시에 세션 정보를 저장할 필요가 없습니다.
작동 원리:
- 사용자가 로그인합니다.
- 서버는 사용자 상세 정보를 포함하는 JWT를 생성하고 비밀 키로 서명합니다.
- 서버는 클라이언트에 JWT를 보냅니다.
- 이후 모든 요청마다 클라이언트는 JWT를 함께 보냅니다.
- 서버는 서명을 검증하고 데이터베이스를 확인하지 않고 내부 데이터를 신뢰합니다.
장점:
- 확장성: 서버가 세션 데이터를 조회할 필요가 없으므로 여러 서버에 걸쳐 수평적으로 확장하기가 더 쉽습니다.
- 성능: 요청마다 발생하는 데이터베이스/캐시 지연 시간을 줄여줍니다.
- 분산화: 서로 다른 서비스가 독립적으로 토큰을 검증할 수 있는 마이크로서비스 아키텍처에 이상적입니다.
단점:
- 철회(Revocation) 문제: 토큰이 발행되면 만료될 때까지 유효합니다. 특정 상태(State)를 도입하지 않고는 만료 전 특정 토큰을 철회(예: 사용자 로그아웃 또는 차단 시)하기가 어렵습니다.
- 토큰 크기: JWT에 너무 많은 데이터를 저장하면 헤더가 커져 모든 HTTP 요청의 오버헤드가 증가할 수 있습니다.
2. 스테이트풀(Stateful) JWT 구현
스테이트풀 구현은 JWT의 휴대성과 전통적인 세션의 제어력을 결합한 방식입니다. 이 모델에서 JWT는 대개 고유한 세션 ID를 포함하며, 서버는 데이터 저장소(Redis 또는 SQL 데이터베이스 등)에 활성 세션 기록을 유지합니다.
작동 원리:
- 사용자가 로그인합니다.
- 서버는 데이터베이스에 세션 레코드를 생성하고 세션 ID가 포함된 JWT를 생성합니다.
- 서버는 클라이언트에 JWT를 보냅니다.
- 모든 요청마다 클라이언트는 JWT를 보냅니다.
- 서버는 서명을 검증하고 데이터베이스/캐시를 확인하여 세션이 여전히 유효하고 활성화되어 있는지 확인합니다.
장점:
- 즉각적인 철회: 데이터베이스에서 세션을 삭제하여 즉시 무효화할 수 있습니다.
- 더 나은 제어: “모든 기기에서 로그아웃"이나 활성 사용자 수 모니터링과 같은 기능을 쉽게 구현할 수 있습니다.
- 보안: 토큰을 도난당한 경우 즉시 블랙리스트에 올릴 수 있습니다.
단점:
- 확장성 저하: 모든 요청마다 데이터베이스나 캐시 조회가 필요하므로 병목 현상이 발생할 수 있습니다.
- 인프라 오버헤드: 가용성이 높은 세션 저장소를 유지 관리해야 합니다.
3. 어떤 것을 선택해야 할까요?
| 특징 | 스테이트리스 JWT | 스테이트풀 JWT |
|---|---|---|
| 확장성 | 높음 | 중간 |
| 철회(Revocation) | 어려움 | 즉각적 |
| 복잡성 | 낮음 | 높음 |
| 성능 | 빠름 | 느림 |
스테이트리스 JWT를 사용해야 하는 경우: 수평적 확장이 최우선 순위이고 짧은 토큰 수명(리프레시 토큰 포함)이 허용되는 고트래픽 API를 구축하는 경우.
스테이트풀 JWT를 사용해야 하는 경우: 보안이 가장 중요하며, 사용자를 즉시 플랫폼에서 퇴출시키거나 사용자당 여러 개의 활성 세션을 관리해야 하는 기능이 필요한 경우.