Jwt vs. Session-based Auth
기본 개념
JWT(JSON Web Token)
JWT는 당사자 간에 정보를 JSON 객체로 안전하게 전송하기 위한 방식이다. 이 정보는 디지털 서명되어 있어 신뢰할 수 있으며, 토큰 자체에 필요한 모든 정보를 포함하고 있다. JWT는 주로 상태 비저장(Stateless) 인증 메커니즘으로 사용된다.세션 기반 인증
세션 기반 인증은 서버가 사용자의 인증 상태를 유지하는 전통적인 인증 방식이다. 사용자가 로그인하면 서버는 세션 ID를 생성하고 이를 서버 메모리나 데이터베이스에 저장한다. 이 세션 ID는 쿠키를 통해 클라이언트에게 전달되며, 후속 요청에서 클라이언트는 이 쿠키를 전송하여 인증 상태를 유지한다.
작동 원리
JWT 인증 흐름
- 사용자가 자격 증명(아이디/비밀번호)을 제출하여 로그인한다.
- 서버는 자격 증명을 확인하고, 서명된 JWT를 생성한다.
- 서버는 JWT를 클라이언트에게 반환한다.
- 클라이언트는 JWT를 저장하고(주로 로컬 스토리지나 쿠키), 이후 요청에 이 토큰을 Authorization 헤더에 포함시킨다.
- 서버는 JWT의 서명을 검증하고 토큰 내 정보를 기반으로 사용자를 인증한다.
- 보호된 리소스에 대한 접근이 허용된다.
세션 기반 인증 흐름
- 사용자가 자격 증명(아이디/비밀번호)을 제출하여 로그인한다.
- 서버는 자격 증명을 확인하고, 고유한 세션 ID를 생성한다.
- 서버는 세션 ID와 연관된 사용자 데이터를 서버 메모리나 데이터베이스에 저장한다.
- 서버는 세션 ID를 쿠키를 통해 클라이언트에게 전송한다.
- 클라이언트는 이후 요청에 자동으로 쿠키를 포함시킨다.
- 서버는 쿠키에서 세션 ID를 추출하고 저장된 세션 데이터와 대조하여 사용자를 인증한다.
- 인증 후 보호된 리소스에 대한 접근이 허용됩니다.
구조와 구성 요소
- JWT 구조
JWT는 세 부분으로 구성되며, 각 부분은 점(.)으로 구분된다.- 헤더(Header): 토큰 타입과 사용된 서명 알고리즘(예: HMAC SHA256, RSA)을 명시한다.
- 페이로드(Payload)**: 토큰에 포함될 클레임(사용자 ID, 이름, 권한 등)을 포함한다.
- 서명(Signature)**: 헤더와 페이로드를 인코딩한 값에 비밀 키를 사용하여 서명함으로써 토큰의 무결성을 보장한다.
예시:xxxxx.yyyyy.zzzzz
(헤더.페이로드.서명)
- 세션 구성 요소
- 세션 ID: 사용자 세션을 식별하는 고유한 식별자.
- 세션 저장소: 세션 데이터를 저장하는 서버 측 저장소(메모리, 데이터베이스, 캐시 등).
- 쿠키: 세션 ID를 클라이언트에게 전달하는 HTTP 쿠키.
- 세션 데이터: 서버에 저장된 사용자 관련 정보.
주요 차이점
상태 관리
- JWT: 상태 비저장(Stateless) 방식으로, 서버는 클라이언트 상태를 저장하지 않는다. 모든 필요한 정보가 토큰 자체에 포함된다.
- 세션: 상태 저장(Stateful) 방식으로, 서버는 세션 데이터를 저장하고 관리한다.
데이터 저장 위치
- JWT: 클라이언트 측에 모든 필요한 정보를 저장한다. 서버는 단지 토큰을 검증만 한다.
- 세션: 클라이언트에는 세션 ID만 저장하고, 실제 사용자 데이터는 서버에 저장한다.
확장성
- JWT: 분산 시스템에서 확장성이 뛰어나다. 토큰 자체에 정보가 포함되어 있으므로 서버 간 상태 공유가 필요 없다.
- 세션: 여러 서버 간에 세션 정보를 공유하기 위해 추가적인 메커니즘(Redis, 데이터베이스 등)이 필요하다.
성능
- JWT: 토큰 검증 시 복호화와 서명 확인 과정이 필요하지만, 데이터베이스 조회가 필요 없다.
- 세션: 매 요청마다 세션 저장소에서 세션 데이터를 조회해야 한다.
보안
- JWT: 토큰 자체에 정보가 포함되어 있어, 토큰 탈취 시 정보 노출 위험이 있다(민감한 정보는 포함하면 안 됨).
- 세션: 세션 ID만 클라이언트에 노출되고, 실제 데이터는 서버에 안전하게 보관된다.
만료 및 무효화
- JWT: 토큰에 만료 시간이 내장되어 있으며, 일단 발급된 토큰은 만료 전까지 무효화하기 어렵다.
- 세션: 서버에서 언제든지 세션을 무효화할 수 있으며, 세션 타임아웃을 동적으로 관리할 수 있다.
장단점
JWT
- 장점
- 확장성: 분산 시스템과 마이크로서비스 아키텍처에 적합하다.
- 서버 부하 감소: 세션 저장소가 필요 없어 서버 메모리를 절약할 수 있다.
- 교차 도메인 지원: 다양한 도메인 간 인증이 용이하다.
- 모바일 친화적: 모바일 애플리케이션에서 사용하기 좋다.
- 인증 정보 포함: 토큰 자체에 사용자 정보와 권한이 포함되어 있다.
- 단점
- 토큰 크기: 포함된 정보가 많을수록 토큰 크기가 커져 네트워크 오버헤드가 발생한다.
- 보안 위험: 클라이언트에 저장된 정보는 탈취될 수 있으며, 민감한 정보 포함 시 위험하다.
- 토큰 무효화 어려움: 발급된 토큰을 즉시 무효화하기 어렵다(블랙리스트 관리 필요).
- 상태 관리 제한: 사용자 정보 변경 시 토큰에 반영하기 어렵다.
- 토큰 갱신 메커니즘 필요: 장기 인증을 위해 리프레시 토큰 같은 추가 메커니즘이 필요하다.
Session-based Auth
- 장점
- 즉각적인 무효화: 언제든지 서버에서 세션을 삭제할 수 있다.
- 데이터 보안: 민감한 정보는 서버에만 저장되어 보안성이 높다.
- 동적 데이터 관리: 사용자 정보 변경 시 서버 측 세션 데이터만 업데이트하면 된다.
- 세션 제어 용이: 세션 타임아웃, 동시 로그인 제한 등의 기능을 쉽게 구현할 수 있다.
- 익숙한 구현: 대부분의 웹 프레임워크에서 세션 관리 기능을 기본적으로 제공한다.
- 단점
- 서버 부하: 세션 데이터를 저장하고 관리하는 데 서버 리소스가 필요하다.
- 확장성 문제: 여러 서버 간 세션 공유를 위한 추가 인프라가 필요하다.
- CSRF 취약점: 적절한 보호 장치가 없으면 CSRF(Cross-Site Request Forgery) 공격에 취약하다.
- 성능 영향: 매 요청마다 세션 저장소에 접근해야 하므로 성능 저하가 발생할 수 있다.
- 모바일/API 제한: 쿠키 기반 세션은 일부 모바일 환경이나 API에서 사용하기 어려울 수 있다.
적합한 사용 시나리오
- JWT에 적합한 시나리오
- 마이크로서비스 아키텍처
- 분산 시스템 환경
- 서버리스 아키텍처
- RESTful API 서비스
- 모바일 애플리케이션 백엔드
- 단기 인증이 필요한 경우
- 서버 간 인증이 필요한 경우
- 세션에 적합한 시나리오
- 전통적인 웹 애플리케이션
- 높은 보안이 필요한 환경
- 사용자 세션을 세밀하게 제어해야 하는 경우
- 사용자 데이터가 자주 변경되는 경우
- 즉각적인 로그아웃 기능이 중요한 경우
- 단일 서버 환경
보안 고려사항
- JWT 보안 고려사항
- 적절한 만료 시간 설정: 짧은 만료 시간을 설정하여 토큰 탈취 위험을 줄인다.
- HTTPS 사용: 토큰 전송 시 항상 HTTPS를 사용하여 전송 중인 토큰이 탈취되지 않도록 한다.
- 민감한 정보 제외: 토큰에 비밀번호나 민감한 개인 정보를 포함하지 않는다.
- 강력한 서명 알고리즘 사용: 안전한 알고리즘(예: RS256)과 충분한 키 길이를 사용한다.
- 리프레시 토큰 보호: 리프레시 토큰은 보안을 강화하여 별도로 관리한다.
- 세션 보안 고려사항
- 안전한 세션 ID 생성: 충분히 길고 예측 불가능한 세션 ID를 생성한다.
- 세션 쿠키 보안: Secure, HttpOnly, SameSite 속성을 설정하여 쿠키 보안을 강화한다.
- 세션 타임아웃 설정: 적절한 세션 만료 시간을 설정한다.
- CSRF 방어: 토큰 기반 CSRF 방어 메커니즘을 구현한다.
- 세션 고정 공격 방지: 인증 후 세션 ID를 재생성한다.
실제 구현 예시
JWT 구현 예시 (Node.js)
|
|
세션 기반 인증 구현 예시 (Node.js)
|
|
하이브리드 접근 방식
최근에는 JWT와 세션 인증의 장점을 결합한 하이브리드 접근 방식도 사용된다:
- JWT + 리프레시 토큰: 짧은 만료 시간의 JWT 액세스 토큰과 서버에 저장하는 리프레시 토큰을 함께 사용하여 보안과 편의성을 균형 있게 유지한다.
- JWT를 세션 저장소와 함께 사용: JWT 토큰을 발급하면서도 서버 측 세션 저장소에 토큰의 유효성을 관리하여 필요시 즉시 무효화할 수 있게 한다.
- 세션 클러스터링: 여러 서버 간에 세션을 공유하기 위해 Redis와 같은 인메모리 데이터 저장소를 사용하여 확장성 문제를 해결한다.
Jwt vs. Session-based Auth
특성 | JWT | 세션 기반 인증 |
---|---|---|
상태 관리 | Stateless (상태 비저장) | Stateful (상태 저장) |
데이터 저장 위치 | 클라이언트 측 | 서버 측 |
확장성 | 높음 (서버 간 공유 필요 없음) | 낮음 (세션 클러스터링 필요) |
서버 부하 | 낮음 | 높음 |
메모리 사용 | 클라이언트: 높음, 서버: 낮음 | 클라이언트: 낮음, 서버: 높음 |
보안 (정보 저장) | 중간 (정보가 클라이언트에 저장) | 높음 (정보가 서버에만 저장) |
토큰/세션 크기 | 클 수 있음 (포함된 데이터에 따라) | 작음 (세션 ID만) |
세션 무효화 | 어려움 (별도 메커니즘 필요) | 쉬움 (서버에서 즉시 가능) |
CSRF 취약성 | 낮음 (Authorization 헤더 사용 시) | 높음 (별도 보호 필요) |
XSS 취약성 | 높음 (토큰 탈취 위험) | 중간 (HttpOnly 쿠키 사용 시) |
구현 복잡성 | 중간 | 낮음 (프레임워크 지원) |
서드파티 지원 | 우수함 (광범위한 라이브러리) | 우수함 (표준 메커니즘) |
모바일/API 호환성 | 우수함 | 제한적 |
만료 처리 | 자체 포함 (exp 클레임) | 서버에서 관리 |
요청 오버헤드 | 높음 (큰 토큰 전송) | 낮음 (작은 세션 ID만 전송) |
사용자 정보 업데이트 | 어려움 (새 토큰 발급 필요) | 쉬움 (세션 데이터만 업데이트) |
적합한 아키텍처 | 마이크로서비스, 분산 시스템 | 모놀리식, 단일 서버 환경 |
백엔드 자유도 | 높음 (다양한 언어/프레임워크) | 중간 (세션 저장소 필요) |
인증 방식 | 토큰 기반 | 쿠키 기반 |
로그아웃 처리 | 복잡함 (클라이언트에서 삭제, 블랙리스트 관리) | 간단함 (서버에서 세션 삭제) |
확장 기능 | 제한적 | 다양함 (세션 데이터 동적 관리) |
동시 접속 제어 | 어려움 | 쉬움 |
용어 정리
용어 | 설명 |
---|---|