RefreshToken을 이용하여 AccessToken 재발급하기(feat. Redis)

밀크야살빼자·2024년 7월 12일
0

AccessToken만 사용하면 잦은 토큰 만료로 인해 사용자는 그때마다 로그인 해야하는 불편함이 있습니다. 최근에는 한번의 로그인으로 유지할 수 있도록 하여 사용자 경험을 향상시킵니다.따라서 AccessToken 유효시간은 짧게, RefreshToken 유효시간은 길게 설정하려고 합니다!

AccessToken과 RefreshToken 저장 위치

1. 로컬 스토리지 or 세션 스토리지

리팩토링 전에는 AccessToken을 브라우저의 세션 스토리지에 저장했습니다. 로그인 성공 시 토큰을 세션 스토리지에 저장한 후, 각 요청 시 JavaScript를 사용하여 이를 함께 보냈습니다. 그러나 로컬 스토리지나 세션 스토리지에 토큰을 저장하는 방식은 XSS 공격에 취약합니다.

XSS(Cross Site Scripting)
사용자가 검증되지 않은 외부에서 입력된 데이터가 포함된 웹페이지를 열었을 때 부적절한 스크립트가 실행되는 공격입니다.

2. 쿠키(HTTP Only)

쿠키는 JavaScript로 접근이 가능하기 때문에 보안 설정이 필요합니다. 이를 위해 HTTP Only 옵션을 설정하여 JavaScript에서 쿠키에 접근하지 못하도록 하고, secure 옵션을 설정하여 HTTPS를 통해서만 쿠키가 전송되도록 해야 합니다. 이렇게 하면 쿠키 탈취 위험을 줄이고, HTTPS로 암호화된 통신을 통해 쿠키 값을 안전하게 보호할 수 있습니다.

그러나 쿠키에 토큰을 저장하면 CSRF(Cross-Site Request Forgery) 공격에 취약해질 수 있습니다. XSS(Cross-Site Scripting)는 토큰 값을 직접 탈취할 수 있지만, CSRF는 쿠키에 저장된 토큰을 이용해 사용자가 로그인된 상태에서 공격자가 원하는 작업을 수행하게 만듭니다. 따라서 CSRF 방어를 위해 추가적인 보안 조치가 필요합니다.

적용

AccessToken은 만료 시간을 짧게 설정하여 세션 스토리지에 private 변수로 저장하고, RefreshToken은 쿠키에 저장하여 관리하기로 했습니다. RefreshToken은 AccessToken을 재발급하는 용도로만 사용되며, 다른 자원에 접근할 수 없기 때문입니다. 안전성을 높이기 위해 RefreshToken을 사용하여 AccessToken을 재발급할 때마다, RefreshToken이 데이터베이스에 저장된 것과 동일한지 유효성 검사를 거쳐 재발급하며, 이 과정에서 기존 RefreshToken은 무효화합니다. 또한, 로그아웃 시에는 데이터베이스에서 RefreshToken을 삭제하여 더 이상 사용할 수 없게 합니다.

RefreshToken을 이용하여 AccessToken을 재발급 받는 방법

  1. 프론트엔드에서 요청을 보낼 때, 항상 accessToken과 refreshToken을 함께 전송합니다. 만약 accessToken이 만료되면, refreshToken의 유효성을 확인하여, 유효하다면 인증 절차를 거쳐 새로운 accessToken과 refreshToken을 발급받습니다.
  2. accessToken을 사용하다가 만료로 인해 요청이 실패할 경우, refreshToken을 사용하여 새로운 accessToken과 refreshToken을 발급받고, 이후 요청은 새로 발급받은 accessToken으로 다시 전송합니다.

첫 번째 방법은 RefreshToken을 매 요청마다 노출시켜야 하므로 보안상의 문제가 있다고 판단하여 두 번째 방법을 채택했습니다.

AccessToken 재발급 과정

  1. RefreshToken 유효성 검증
  2. 저장소에 RefreshToken 존재 유무 확인
  3. 1번과 2번 모두 검증되면 재발급 진행
  4. 쿠키에 HttpOnly로 RereshToken 저장
  5. header에 새로 발급한 AccessToken을 저장
    이후 클라이언트는 재발급된 AccessToken을 요청 헤더에 포함하여 전송하면 정상적으로 접근이 허용됩니다.
  • 유효성 검증
    - RefreshToken의 형식이 올바른지 검사
    - RefreshToken의 memberId가 현재 로그인한 memberId와 일치하는지 확인
    - RefreshToken이 저장소에 있는지 검사

  • 토큰 재발급하기

  • 레디스에 RefreshToken 저장

    레디스에 RefreshToken을 저장하는 이유는, 토큰이 만료되더라도 자동으로 삭제되지 않기 때문입니다. 따라서, RefreshToken의 유효 기간을 Redis에 동일하게 설정하여 만료 시 자동으로 삭제되도록 함으로써 시스템의 안정성을 높였습니다.

    Redis란?

    • In-memory 기반의 DB로 메인 메모리에서 데이터를 처리하기 때문에 작업 속도가 매우 빠르다.
    • 휘발성 메모리이다.

      메모리 구조는 위 그림과 같이, 메인 메모리에 필요한 데이터가 없으면 하드 디스크에서 읽어오고, 필요한 데이터가 메인 메모리에 있으면 바로 CPU로 올려 작업을 처리합니다. 즉, 하드 디스크 -> 메인 메모리 -> CPU 순으로 처리됩니다. 디스크에서 데이터를 읽어오는 과정은 I/O 작업이 필요하여 속도가 느리지만, 메인 메모리에 데이터가 있으면 바로 읽어서 사용할 수 있어 속도가 매우 빠릅니다. 이러한 점을 이용해 만든 것이 Redis입니다.
  • 쿠키에 RefreshToken 저장
  • 쿠키에 정상적으로 담겨있는 것을 확인할 수 있습니다.

📚 참고 자료

profile
기록기록기록기록기록

0개의 댓글