백엔드 개발/인증 · 보안

Refresh Token 탈취를 막기 위한 보안 설계: Redis TTL, Rotation, userAgent 바인딩까지

JeongPark 2025. 5. 3. 02:22
728x90

실서비스 기준: Redis + 세션 + RefreshToken 구조를 도입한 이유

1. 도입 배경

사용자가 로그인한 이후에도 안정적으로 인증 상태를 유지하면서도, 보안 문제 없이 동작하는 시스템이 필요했습니다.
특히 아래 같은 문제들을 해결해야 했습니다.

  • 동일 사용자의 중복 로그인 문제
  • Refresh Token 탈취 시 악용 가능성
  • 사용자 세션 만료 시 적절한 UX 대응
  • 로그아웃 시 세션 정리 누락으로 인한 보안 리스크

그래서, 아래와 같은 구조로 시스템을 설계하게 되었습니다.


2. Redis 기반 세션 저장소를 선택한 이유

선택 이유

  • 인메모리 기반으로 세션 TTL 만료에 적합
  • 수만 명의 세션 데이터를 빠르게 읽고 쓸 수 있음
  • 세션 로그아웃, 자동 만료 등을 중앙 집중형으로 제어

내가 정의한 기본 구조

  • Key: session:userId:{id}
  • Value: RefreshToken, IP, UserAgent, 생성 시간
  • TTL: 기본 7일 (로그인 시 연장), Redis의 EX 기능 활용

3. TTL(Time-To-Live)을 설정한 이유

문제

세션이 만료되지 않으면 오래된 로그인 정보가 계속 유효하게 유지됨. 이는 보안상 위험.

목적

  • 사용자의 활동이 없을 경우, 일정 시간 이후 자동 로그아웃
  • 서버 자원 관리
  • 보안 강화를 위한 기본 설정

적용 방식

  • Redis set 시 EX 옵션으로 TTL 설정
  • 새로 로그인하거나, 토큰 갱신 시 TTL 갱신 여부는 기획 정책에 따름

4. Refresh Token Rotation을 도입한 이유

문제

탈취된 Refresh Token으로 재발급 요청 시, 서버가 이를 구분하지 못하면 Access Token을 계속 발급받을 수 있음

해결 전략

  • Refresh Token 사용 시 무조건 새로운 Refresh Token으로 교체
  • 기존 Token은 Redis에서 삭제하여 재사용 불가 처리
  • 클라이언트에 최신 토큰을 전달하는 UX 설계 필요

이 방식의 장점

  • 토큰 도난 시 재사용을 원천 차단
  • 매 요청마다 새로운 토큰으로 보안성 상승
  • Redis에서 마지막 사용 시점, IP, userAgent 로그 관리 가능

5. IP + userAgent 바인딩을 도입한 이유

문제

동일한 Refresh Token이 다른 환경(브라우저/IP)에서 재사용되는 경우 → 탈취로 의심할 수 있음

구조

  • Redis에 저장할 때 userAgent + IP 정보를 같이 저장
  • 토큰 재발급 요청 시, 현재 요청 정보와 일치 여부 확인
  • 다를 경우 재발급 거절 + 로그 기록

추가 효과

  • 중복 로그인 방지
  • 로그인 세션 탈취 여부 감지 가능

6. 하나의 유저당 하나의 세션 유지

목적

  • 멀티 로그인 방지
  • 한 디바이스만 세션 유지 허용
  • 새로 로그인하면 기존 세션 제거 → 보안 강화

7. 실제 적용하면서 느낀 점

  • 초기엔 단순히 JWT 기반 인증만 구현했지만, 실제 운영 환경에서는 세션/토큰 관리가 더 중요
  • Redis TTL, Rotation 정책, IP 바인딩 없이는 보안 문제가 실제로 발생함
  • 특히, 로그아웃 처리 누락, 오래된 세션 재사용 문제가 실제로 발생 → Redis 기반 설계로 해결

8. 마무리

보안과 유지보수 측면에서 RefreshToken과 세션을 어떻게 다루는지는 단순 로그인 기능 이상으로 중요합니다.
Redis TTL, Rotation, 바인딩 등의 전략은 서비스를 안정적으로 운영하기 위한 최소한의 방어선이었습니다.

단순히 동작하는 인증 시스템이 아니라, 운영 가능한 인증 시스템을 구축하려면 반드시 고려해야 할 요소라고 생각합니다.

반응형