티스토리 뷰

728x90

로그인은 됐는데, 왜 또 로그인하라는 걸까?

 

백엔드 API를 처음 설계했을 때

로그인 기능 자체는 비교적 쉽게 구현했습니다.

 

문제는 그 다음이었습니다.

- 새로고침하면 로그인이 풀리고

- 서버를 여러 대로 늘리자 인증 오류가 발생

 

인증이라는게 이렇게까지 어려운 문제였나 . . .?

이 고민의 끝에서 JWT (Json Web Token) 를 제대로 이해하지 않으면 안 되겠구나 느꼈습니다.

 

이 글은 JWT 를

- 왜 쓰게 되었는지

- 어떤 문제를 해결했는 지

- 막연히 쓰다 겪은 시행착오

중심으로 정리한 문제 해결 기록입니다.

 


 

문제 상황 - 세션 기반 인증의 한계에 부딪히다

 

처음 사용했던 방식 : 세션 (Session)

초기 구조는 전형적인 세션 기반 인증이었습니다.

 

1. 로그인 성공

2. 서버에 세션 저장

3. 클라이언트는 세션 ID를 쿠키로 보관

4. 이후 요청마다 세션 확인

 

그런데 실무에서 문제가 터졌습니다.

- 서버를 2대 이상으로 늘리는 순간 -> 특정 서버에서는 로그인 상태가 풀림

- 외부 API 연동 -> 쿠키 기반 인증이 애매해짐

 

로그인 상태를 서버가 계속 기억해야 한다는 점이 확장성과 운영 측면에서 계속 발목을 잡았습니다.

 


 

원인 분석 - 인증 상태를 누가 들고 있어야 하는가

 

" 사용자가 로그인했다는 사실을 누가 기억해야 할까? "

 

세션 방식 -> 서버

JWT 방식 -> 클라이언트

 

이 차이가 모든 구조를 갈랐습니다.

 


 

그럼 JWT가 무엇인가 - 서버의 기억을 토큰으로 옮긴 방식

JWT (Json Web Token)는 인증 정보를 하나의 토큰으로 만들어 클라이언트에게 맡기는 방식입니다.

 

JWT 구조

점(.)으로 구분된 세 부분으로 구성

Header.Payload.Signature

 

Header

- 토큰 타입 (JWT)

- 서명 알고리즘 (HS256 등)

{
  "alg": "HS256",
  "typ": "JWT"
}

 

Payload

- 사용자정보 (claims)

- 만료 시간, 권한 등

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

 

Signature

- Header + Payload + Secret Key

- 위조 여부 검증용


해결 과정 - JWT 기반 인증 흐름으로 재설계

 

로그인 시

  1. 아이디 / 비밀번호 검증
  2. JWT 생성
  3. 클라이언트에 전달
 

이후 요청 시

클라이언트: Authorization 헤더에 JWT 포함

 

서버:

- 토큰 추출

- 서명 검증

- Payload에서 사용자 정보 사용


결과

항목 세션 jwt
서버 상태 상태 저장 필요 무상태(stateless)
서버 확장 까다로움 매우 쉬움
모바일/외부 연동 불편 용이
인증 로직 복잡 단순

 


JWT를 쓰며 겪은 풀어야 할 문제

 

1. 로그아웃이 어렵다

JWT는 서버에 저장되지 않기 때문에 즉시 무효화가 어렵다

-> 해별방식

- Access Tocken + Refresh Token

- 블랙 리스트 관리 ( 이러면 jwt를 쓰는 장점이 없어지지 않나 .. . .? )

 

2. 만료 시간 설계가 중요하다

- 너무 길면 보안 위험

- 너무 짧으면 사용자 경험 저하

 

3. 탈취되면 끝

-> refresh token rotation

 


무조건 JWT가 좋은건 아닌 것 같습니다

단일서버

내부 관리자 페이지

복잡한 권한 관리 필요없는 경우에는

세션이 더 단순하고 안전합니다.

 

JWT는 편리한 인증 도구이지 보안 문제를 대신 해결해 주는 기술은 아닙니다.

세션을 대체하는 게 아니라 상황에 맞는 선택지일 뿐이라고 생각합니다.

이후로는 인증 방식을 정할 때

우리 서비스는 상태를 어디까지 서버가 책임져야 하는가를 먼저 고민하게 되었습니다.

 

다음 포스팅은 

728x90