💻 하나씩 차곡차곡/Back-end

[스프링 시큐리티] 서버 기반 인증 VS 토큰 기반 인증 (Session, JWT 등)

뚜루리 2025. 4. 21. 17:37
728x90
320x100
인증 방식엔 크게 서버 기반 인증과 토큰 기반 인증으로 나뉜다. 

 

인증? 왜 하는건데요?

🔓 인증을 안 하면?

  • 누구든지 API 요청을 제한 없이 보낼 수 있음
  • 로그인을 하지 않아도 개인 정보, 글 수정/삭제, 주문 등 모든 기능에 접근 가능
  • 내가 누군지 증명하지 않기 때문에 보안이 완전히 무너짐

✅ 인증이 필요한 이유

  • 클라이언트가 보내는 요청이 진짜 로그인한 사용자인지 서버가 확인해야 함
  • 인증이 있어야 접근 권한, 개인화 정보, 보안 처리가 가능함

 


 

[🔐 인증 방식 분류]

1. 서버 기반 인증 (Server-Side Authentication)

서버가 사용자 인증 상태를 기억하고 있음 (Stateful)

  • 대표 방식: 세션 기반 인증 (Session-based Authentication)
    → 서버에 로그인한 사용자의 세션 정보를 저장하고, 클라이언트는 세션 ID로 인증
  • 특징:
    • 인증 상태를 서버가 관리
    • 세션 저장소 필요 (메모리, Redis 등)
    • 로그아웃, 세션 만료 등 제어가 쉬움

 

2. 토큰 기반 인증 (Token-based Authentication)

인증 정보를 토큰에 담아 클라이언트가 관리 (Stateless)

  • 대표 방식 : JWT 기반 인증 (JWT-based Authentication)
    → 서버에서 서명된 JWT 토큰을 발급하고, 이후 요청 시 클라이언트가 헤더에 담아서 인증
  • 특징:
    • 서버는 인증 상태를 기억하지 않음
    • 토큰 자체에 인증 정보를 포함
    • 확장성과 외부 API 연동에 유리

 


 

1-1. 세션 기반 인증 (Session-based Authentication)

작동 흐름

  1. 사용자가 로그인
  2. 서버가 HttpSession 생성하고, 세션 ID 클라이언트에 Set-Cookie: JSESSIONID=abc123
  3. 클라이언트는 이후 요청마다 해당 쿠키를 자동으로 전송
  4. 버는 세션 ID 확인해서 인증된 사용자로 처리

장점

  • 버에서 세션 만료 및 로그아웃 처리 등 인증 상태를 쉽게 제어할 수 있음.
  • 토큰보다 보안적으로 유리한 경우가 많음.
    • why? 세션 ID는 서버에서 관리되기 때문에 유출되도 서버에서 강제로 무효화(로그아웃, 만료)시키는게 가능.
    • 만료시간, 로그인제한, 강제 로그아웃 관리가 가능해서 유출되더라도 피해를 줄일 수 있음.
    • 쿠키에 HttpOnly, Secure 설정을 하면 자바스크립트에서 쿠키 접근이 불가능해서 XSS 공격방어도 가능.
    • But, JWT의 경우 클라이언트가 토큰을 갖고 있기 때문에 서버에서 토큰 무효화가 바로 되지 않음.
  • 클라이언트 쪽은 특별한 저장소 없이 쿠키만 사용하면 되므로 단순함.

단점

  • 사용자가 많아지면 서버 세션 저장소의 부하가 증가함
  • 서버를 여러 대로 확장할 경우 세션 공유 또는 클러스터링 처리가 필요함.
  • 모바일, API 기반 서비스에는 사용이 불편할 수 있음.
    • why? 모바일이나 API 클라이언트는 쿠키 자동 처리 지원이 부족하거나 제한적임. 세션의 경우 서버에 저장소가 필요해서 API요청이 많고 서버가 여러개면 세션 공유가 복잡해짐 게다가 REST API는 일반적으로 무상태를 추구하는데 세션은 상태 기반이라 어울리지 않음.

 


2-1. JWT 인증

  • JWT는 자체적으로 사용자 정보와 만료 시간 등을 포함한 자체 완결형 구조

 

작동 흐름

  1. 사용자가 로그인
  2. 서버가 검증 JWT 토큰 발급
  3. 클라이언트는 토큰을 Authorization: Bearer <token> 헤더에 담아 요청
  4. 서버는 요청마다 토큰을 검증해서 인증된 사용자 처리
[로그인] → [JWT 발급] → [JWT 들고 요청] → [필터가 검사] → [통과 시 인증 완료] → [API 접근 허용]

 

장점

  • 서버 저장소 없이도 인증이 가능하므로 확장성과 성능이 뛰어남.
  • 마이크로서비스, 모바일, 프론트엔드 분리 구조에서 유리함.
  • 서버 간 인증 상태 공유가 필요 없어 로드밸런싱이나 API 서버 확장에 적합함.

단점

  • 토큰 탈취 시 만료 전까지 무제한 사용 가능하여 보안에 취약할 수 있음.
  • 로그아웃 처리나 토큰 무효화 처리가 어려움. (보통 블랙리스트나 Redis 도입 필요)
  • 토큰 길이가 길고, 재발급 및 갱신 관리가 추가로 필요함.

 

JWT기반 인증 방식은 CSRF기능을 반드시 꺼줘야 한다 왜?

  • Spring Security는 POST 요청 등에서 CSRF 토큰 검증을 강제함
  • 하지만 JWT 기반은 그런 방식(X-CSRF-Token)이 아니라, 헤더에 토큰을 담기 때문에 CSRF 토큰이 없음
  • 그래서 Spring Security는 “위험한 요청인데 CSRF 토큰이 없네?” → 요청 차단

 

http.csrf(csrf -> csrf.disable());

 

AccessToken과 RefreshToken

항목 Access Token Refresh Token
목적 API 요청 인증 (매 요청마다 사용) AccessToken이 만료되었을 때 새로운 AccessToken을 발급받기 위해 사용
유효 기간 짧음 (보통 15분~1시간) 김 (보통 7일~2주)
저장 위치 클라이언트 (localStorage, sessionStorage, 또는 쿠키) 보안상 서버(DB/Redis) 에 저장하는 것이 권장됨
유출 시 피해 짧은 시간 동안만 악용 가능 매우 심각함 → 서버 저장 및 관리 필수
재발급 기능 없음 → 만료되면 재로그인 필요 AccessToken 재발급 가능
보안 제어 서버는 관리하지 않음 (stateless) 서버에서 직접 관리 가능 (blacklist, 삭제 등)
인증 방식 요청마다 헤더에 담아서 보내기 (Authorization: Bearer 토큰) 주로 재발급 API에만 사용 (/token/refresh)

 

🔄 둘 다 왜 필요한가?

✅ AccessToken만 쓴다면?

  • 유출 시 제한된 시간만 공격 가능 (보안상 안전)
  • BUT, 짧게 설정하면 사용자는 계속 로그인해야 해서 불편

✅ RefreshToken만 쓴다면?

  • 매번 요청마다 RefreshToken 쓰는 건 위험!
  • 유출되면 긴 시간 동안 무한 재발급 가능 → 큰 보안 리스크

🔐 그래서 조합해서 사용

  • AccessToken: API 요청 인증에 사용 (빠르고 가볍게)
  • RefreshToken: AccessToken 만료됐을 때만 사용 (드물게, 안전하게)

이 구조는 "보안과 사용자 경험을 둘 다 만족시키기 위한 전략"

 

 


 

 

정리

항목 세션 기반 JWT 기반
저장 위치 서버 메모리 or Redis 클라이언트 (브라우저 등)
상태 유지 서버가 상태를 기억해야 함 (Stateful) 서버는 상태를 기억하지 않음 (Stateless)
확장성 세션 공유 문제로 서버 간 동기화 필요 토큰만 있으면 인증 가능 → 서버 확장에 유리
보안 세션 탈취 시 위험, 쿠키 설정 중요 (HttpOnly, Secure 등) 토큰 유출 시 위험, 만료 시까지 유효
관리 편의성 세션 삭제로 강제 로그아웃 등 쉬움 토큰은 클라이언트가 관리 → 만료 전까지 제어 어려움
만료 처리 서버에서 쉽게 제어 가능 토큰 자체에 만료 정보 포함, 중간 강제 만료 어려움

*** 스프링 시큐리티는 모두 지원 (세션은 기본, JWT는 확장 구성이 필요)

 


 

🧠 언제 어떤 걸 써야 할까?

상황 추천 방식
소규모 서비스 세션 기반으로 빠르게 구현 가능
분산 서버 구조 (무상태성) JWT가 유리 (확장성, 로드밸런싱에 유리)
민감 정보 관리, 보안 중요 세션 기반이 더 안전 (만료 및 강제 로그아웃 제어 가능)
모바일, 외부 API 연동 많음 JWT가 적합 (Stateless 인증)
728x90
320x100