▼ Why ?
오늘은 Spring Security에서 "세션(Session)을 기반으로 하는 인증"과 "JWT 토큰을 기반으로 하는 인증"의 차이점에 대해 알아보고 정리해보려고
▼ 세션(Session) 기반 인증
Session 기반 인증/인가 처리 절차
STEP 1: 사용자 인증 과정
- 인증 요청 ➙ 인증 필터 ➙ 인증 관리자(AuthenticationManager) ➙ 사용자 세부 정보 로드 후 비교 ➙ 인증 완료
STEP 2: Session 생성 및 관리
- 서버에서 앞선 인증에 성공하여 메모리에 사용자 정보를 저장하게 된다.
➙ Spring Security는 해당 사용자를 위한 "HTTP Session"을 생성한다.
➙ "Authentication 객체"를 담고 있는 사용자의 현재 "SpringContext"를 담고 있는 "SecurityContextHolder"가 있다.
➙ 이를 통해 필요할 때마다 사용자의 인증 정보에 접근하는 것이다 ! - 그리고 사용자의 브라우저(클라이언트) 측으로 해당 Session의 ID가 포함된 Session "쿠키(Cookie)"를 전송한다.
➙ 클라이언트에서의 각 요청들은 이 쿠키와 함께 서버로 전송하므로 서버에서 로그인 자격 증명을 클라이언트에 다시 요구하지 않고도 일치하는 Session ID를 검색하여 자동으로 사용자를 인증할 수 있는 것이다 !
STEP 3: 접근 제어 및 승인
- 사용자가 인증되고 Session이 설정된 후 Spring Security는 Authentication 객체에 저장된 사용자의 권한(GrantedAuthority)를 기반으로 해당 사용자의 접근 권한을 결정한다.
STEP 4: 로그아웃 절차
- Spring Security는 사용자 Session을 무효화하는 사용자 로그아웃을 지원한다.
➙ 로그아웃 요청을 받으면 로그아웃 프로세스(SecurityContext 삭제, HTTP Session 무효화, 사용자를 로그아웃 성공 페이지로 리디렉션, ...)를 처리하는 LogoutFilter를 트리거(trigger)한다.
[ 참고 자료 - Session 인증/인가 과정 ]
[Spring] 스프링 시큐리티(Spring Security)
▼ Why ?이번에 토이 프로젝트를 하면서 스프링 시큐리티 이용한 로그인을 구현하려고 하는데, 스프링 시큐리티에 대한 이해가 많이 부족하다고 느껴서 제대로 다시 공부해보려고 한다!▼ What ?Sp
ukym-tistory.tistory.com
Session 기반 인증의 이점과 문제점
Session 기반 인증의 이점
- Session 정보가 서버 측에 저장되므로 브라우저나 모바일 앱의 메모리를 절약할 수 있다.
- 서버 측에서 유저의 인증 정보를 관리하기 때문에, 보안성이 높다.
Session 기반 인증의 문제점
- 각 사용자 Session에는 저장을 위한 서버 메모리가 필요하며, 이는 동시 사용자 수가 증가함에 따라 리소스 소비가 크게 증가할 수 있다.
➙ 이로 인해 사용자 기반이 큰 애플리케이션의 경우 확장성 문제가 발생할 수 있다. - 로드 밸런서(Load Balancer)는 동일한 사용자의 모든 요청을 Session이 저장된 동일한 서버로 라우팅하기 위해 "고정 세션(Session Affinity)"을 구현해야 하는 경우가 많습니다.
➙ 이로 인해 서버 전체에 로드를 균등하게 분산하는 기능이 제한되고 로드 밸런싱의 효율성이 감소할 수 있다.
Session 기반 인증의 문제점을 해결하기 위한 "세션 클러스터링(Session Clustering)"
Session Clustering ?
- Cluster의 여러 서버에 사용자 Session 데이터를 분산시키는 방식을 의미합니다.
➙ 서버 Cluster 전체에서 Session 데이터를 사용할 수 있고 일관되게 유지함으로써 웹 애플리케이션의 안정성, 확장성 및 전반적인 사용자 경험을 향상시키기 위함 ! - Session Clutering을 지원하는 기술
- 몇몇 애플리케이션 서버(Application Server)에선 기본적으로 지원한다.
(ex: Apache Tomcat, WildFly 및 IBM WebSphere) - In-Memory Grid(ex: Redis, Hazelcast, Apache Ignite, ...)나 NoSQL Database는 "중앙 집중식 Session 저장소" 역할을 할 수 있다.
- 클라우드 서비스는 클러스터 환경에서 로드 밸런싱(Load Balancing) 및 세션 스토리지(Session Storage)를 위한 관리형 솔루션을 제공합니다.
(ex: AWS Elastic Load Balancing, Amazon ElastiCache, Azure Load Balancer, Azure Redis Cache, Google Cloud Load Balancing)
- 몇몇 애플리케이션 서버(Application Server)에선 기본적으로 지원한다.
"Session Clustering"의 목적
- 고가용성
: Cluster에 있는 하나 이상의 서버에 장애가 발생하더라도 애플리케이션이 계속 액세스 가능하고 작동하도록 보장한다. - 로드 밸런싱(Load Balancing)
: 사용자 요청을 여러 서버에 분산하여 많은 수의 동시 사용자를 처리하는 애플리케이션의 능력을 향상시킨다. - 내결함성
: 사용자 세션에 중복성을 제공하여 서버가 다운되더라도 세션이 손실되지 않도록 한다. - 확장성: Cluster에 더 많은 서버를 추가하여 애플리케이션 아키텍처를 크게 변경하지 않고도 증가된 로드를 처리할 수 있습니다.
"Session Clustering"의 작동 방식

- 사용자 Session 생성
: 사용자가 웹 애플리케이션과 상호 작용할 때 인증 상태, 사용자 기본 설정, 애플리케이션 상태 등
사용자별 데이터를 저장하기 위해 서버에 Session이 생성된다.
➙ 이 세션은 동일한 사용자의 여러 요청에서 액세스할 수 있어야 한다. - 세션 복제
: 세션 클러스터링 설정에서 한 서버에서 세션이 생성되거나 업데이트되면 세션 데이터가 클러스터의 다른 서버에 아래와 같은 다양한 방식으로 복제된다.
- 고정 세션(Session Affinity)
: 로드 밸런서(Load Balancer)는 동일한 사용자 Session의 모든 요청을 세션이 생성된 동일한 서버로 라우팅한다.
하지만, "내결함성"을 위해 Session 데이터가 서버 전체에 계속 복제될 수 있습니다. - 세션 복제
: 각 세션 업데이트는 Cluster의 전체 또는 일부 서버에 복제되므로 모든 서버가 모든 세션에 대한 요청을 처리할 수 있다. - 중앙 집중식 세션 저장소
: 서버 간에 Session을 복제하는 대신 Cluster의 모든 서버가 액세스할 수 있는 중앙 집중식 데이터 저장소(ex: Database, In-Memory Data Grid)에 Session이 저장됩니다.
- 고정 세션(Session Affinity)
- 로드 밸런싱(Load Balancing)
: 로드 밸런서(Load Balancer)는 일반적으로 다양한 알고리즘(ex: Round-Robin, 최소 연결 또는 IP 해시)과 서버의 현재 로드를 기반으로 Cluster의 서버에 들어오는 사용자 요청을 분산하는 데 사용됩니다. - 세션 장애 조치
: 서버 장애가 발생한 경우 Cluster의 다른 서버가 장애가 발생한 서버 Session에 대한 요청을 인계받아 계속해서 처리할 수 있도록 보장해준다.
"Session Clustering"에 대해 주의해야 할 점
- 일관성(Consistency) vs. 성능(Performance)
: 서버 간에 Session 데이터를 복제하면 대기 시간이 발생하고 추가 네트워크 대역폭이 필요할 수 있다.
일관성과 성능의 균형을 맞추려면 올바른 Session 복제 전략을 선택하는 것이 중요하다. - Session 저장소
: "고정 세션", "Session 복제 및 중앙 집중식 Session 저장소" 간의 선택은 특정 애플리케이션 요구 사항과 복잡성, 성능 및 내결함성 간의 균형에 따라 달라집니다. - 보안
: 중요한 사용자 정보를 보호하려면 세션 데이터가 클러스터 전체에 안전하게 전송되고 저장되는지 확인하는 것이 필수적입니다.
▼ JWT 기반 인증
JWT ?
JWT(Json Web Token)
- 사용자가 인증을 요청(로그인)하고 인증이 완료되면 서버에서 토큰을 발행해주게 되는데, 이때 이 토큰이 바로 "JWT"이다 !
➙ 그리고 이 토큰을 클라이언트(브라우저)의 저장소에 토큰을 유지시키는 방식이 "JWT 기반 인증"이다. - JWT는 인증에 필요한 정보들을 암호화시킨 것이라 보면 되고, 이 JWT를 HTTP 헤더(Header)에 실어 전송하게 되면 서버가 클라이언트를 식별할 수 있다.
JWT 구조
- JWT는 "."을 구분자로 나누어 세 가지 문자열의 조합으로 구성되어 있다.
- 헤더(Header)
➙ JWT에서 사용할 타입과 해시 알고리즘(ex: HS256, RSA)의 종류가 담겨있다. - 내용(Payload)
➙ 서버에서 첨부한 사용자 권한(인가) 정보와 데이터가 담겨있다. - 서명(Signature)
➙ Header, Payload를 "Base64 URL-safe Encode"를 한 이후에 Header에 명시된 해시함수를 적용하고, 개인키(Private Key)로 서명한 전자서명이 담겨있다.
( 전자서명엔 비대칭 암호화 알고리즘을 사용하므로 암호화(전자서명)엔 개인키를, 복호화(검증)에는 공개키를 사용한다. )
JWT를 이용한 인증 과정
- 사용자가 ID, PW를 입력하여 서버에 인증(로그인)을 요청한다.
- 서버에서 클라이언트로부터 인증 요청을 받으면, Header, PayLoad, Signature를 정의한다.
➙ Header, PayLoad, Signature를 각각 Base64로 한 번 더 암호화하여 JWT를 생성하고 이를 쿠키(Cookie)에 담아 클라이언트에게 발급한다. - 클라이언트는 서버로부터 받은 JWT를 브라우저 저장소에 저장한다.
(ex: 로컬 스토리지(Local Storage), 세션 스토리지(Session Storage), 쿠키(Cookie))
➙ API를 서버에 요청할때 Authorization header에 Access Token을 담아서 보낸다. - 서버가 할 일은 클라이언트가 Header에 담아서 보낸 JWT가 해당 서버에서 발행한 토큰인지 검증하여
일치한다면 인증을 통과시키고 아니라면 통과시키지 않는다.
➙ 인증에 성공했으면 Payload에 들어있는 유저의 정보들을 DB에서 select하여 클라이언트에 반환해준다. - 클라이언트가 서버에 요청을 했는데, 만일 Access Token의 시간이 만료되었다면
클라이언트는 Refresh Token을 이용해서 서버로부터 새로운 Access Token을 발급 받는다.
💡 로컬 스토리지(Local Storage), 세션 스토리지(Session Storage), 쿠키(Cookie) ?
로컬 스토리지(Local Storage)와 세션 스토리지(Session Storage)는 브라우저에 내장된 클라이언트 측 저장소로,
Local Storage는 사용자가 직접 삭제하지 않는 한 영구적으로 유지되고, Session Storage는 브라우저 Session이 유지되는 동안만 유지된다.
쿠키(Cookie)는 브라우저를 종료해도 유지될 수 있으며, 만료 날짜가 지나면 삭제된다.
보안 상의 이유로 "쿠키(Cookie)"를 사용하는 것이 권장된다 !
하지만, HTTPS와 같은 보안 프로토콜을 사용하고, CSRF 공격에 대한 보호 기능을 추가하여 JWT를 더 안전하게 저장해주어야 한다 !
▼ 세션 클러스터링(Session Clustering) vs. JWT
Session Clustering
강점
- 상태 유지(⭤ stateless)
: Session 데이터는 서버나 공유 데이터 저장소에 저장되므로 요청 전반에 걸쳐 사용자 상태를 간편하게 추적하고 관리할 수 있습니다. - 중앙 집중식 로그아웃
: 서버 측에서 세션이 무효화될 수 있으므로 사용자 세션을 종료하는 것이 간단하다. - 민감한 데이터
: 세션 데이터가 서버에 저장되므로 민감한 정보가 클라이언트에 노출되지 않아 보안이 강화된다.
약점
- 확장성
: Session Clustering은 확장성을 해결할 수 있지만 특히 세션 수가 증가함에 따라 Session 복제 또는 중앙 집중식 Session 저장소를 관리하려면 추가적인 인프라와 복잡성이 필요하다. - 서버 로드
: Session 데이터를 저장하고 관리하면 특히 동시 사용자 수가 많은 경우 서버나 데이터 저장소에 상당한 로드가 발생할 수 있다.
JWT 토큰 인증
강점
- 상태 비저장
: JWT는 자체 포함되어 있으며 서버에서 Session 데이터를 조회할 필요 없이 유효성을 검사할 수 있다.
➙ 이는 HTTP의 상태 비저장 특성(Stateless)와도 일치하는 방식이라 확장성을 향상시킬 수 있다 ! - 교차 도메인 인증
: JWT를 사용하면 공유 Session 저장소 없이도 SSO(Single Sign-On) 및 교차 도메인 인증을 더 쉽게 구현할 수 있다. - 성능
: 토큰에는 요청을 인증하고 승인하는 데 필요한 모든 정보가 포함되어 있으므로 모든 요청에서 Database 또는 공유 데이터 저장소를 조회할 필요성이 줄어든다.
💡 SSO(Single Sign-On; 통합인증)
한 번의 인증 과정(로그인)으로 여러 컴퓨터 상의 리소스를 이용 가능하게 하는 인증 기능이다.
예를 들면, Google 아이디 하나로 Google의 여러 서비스(Google Drive, Gmail, Google Photo 등)들을 이용하는 것도 SSO를 도입함으로써 가능해진 사례이다.
약점
- 토큰 취소
: 토큰은 자체적으로 포함되어 있으므로 만료되기 전에 JWT를 취소하는 것이 복잡하다.
( 토큰 취소 메커니즘을 구현하려면 토큰 거부 목록을 유지하고 상태 저장 기능을 다시 도입해야 할 수 있다. ) - 토큰 저장소
: 클라이언트 측에 토큰을 안전하게 저장하고(XSS 공격 방지) 토큰이 안전하게 전송되도록 보장(CSRF 공격 방지)하기 위해 신중하게 구현할 필요가 있다 ! - 토큰 크기
: 너무 많은 정보가 포함되면 JWT가 커져 HTTP 헤더(Header) 크기와 전체 네트워크 성능에 영향을 미칠 수 있다.
결론
- "Session Clustering"과 "JWT 인증" 간의 선택은 확장성, 보안, 인프라 및 사용 가능한 개발 리소스를 포함한 애플리케이션의 특정 요구 사항을 기반으로 해야 한다 !
- 애플리케이션 요구 사항
: 애플리케이션에 세션 데이터를 즉시 무효화하고 관리하는 기능과 함께 Session에 대한 세밀한 제어가 필요한 경우 Clustering을 사용한 Session 기반 인증이 더 적합할 수 있습니다.
( 서버 측 Session 관리가 이미 구현되어 있는 기존 웹 애플리케이션에 선호되는 경우가 많다. ) - 확장성 및 상태 비저장
: 여러 서버나 도메인에 걸쳐 확장이 필요한 분산 시스템, 마이크로서비스 또는 애플리케이션의 경우 JWT 인증은 확장성과 유연성 측면에서 이점을 제공한다. - 보안 및 성능
: JWT에는 강력한 토큰 관리 및 보호 전략이 필요한 반면,
Session Clustering에는 안전한 Session 데이터 관리가 필요하며 Session 데이터 저장소 관리가 복잡해질 수 있다.
- 애플리케이션 요구 사항