본문으로 건너뛰기

연속 새로고침으로 인한 토큰 갱신 실패 이슈(동시성)

관리인
관리인2025년 3월 27일2 분
스크린샷 2025-03-29 오후 5.14.51.png

문제 제기

연속적인 페이지 새로고침 시 로그인 상태가 풀리는 현상이 발생함. 특히 3초 정도 Ctrl+R을 연속으로 누르고 있을 때 "유효하지 않은 리프레시 토큰입니다"라는 오류와 함께 로그아웃됨. 그러나 몇 초 간격을 두고 새로고침할 때는 이러한 문제가 발생하지 않음. 개인적으로 정해놓은 기한에 쫒기다 보니 동시성 이슈에 대해 고려하지 못하였음.

원인 분석

  • 토큰 로테이션 충돌:

    • 서버는 토큰 갱신 시 액세스 토큰뿐만 아니라 리프레시 토큰도 함께 교체(로테이션)함

    • 연속 새로고침 시 동일한 리프레시 토큰으로 여러 요청이 거의 동시에 서버에 도달함

    • 첫 번째 요청이 처리되면 해당 리프레시 토큰은 무효화되고 새 토큰이 발급됨(아직 클라이언트는 발급된 토큰을 전역상태에 할당하지 못함

    • 거의 동시에 도착한 두 번째 요청은 이미 무효화된 리프레시 토큰을 사용하므로 인증 실패 발생. 서버가 401(권한없음) 반환

    • 401 응답을 받은 클라이언트가 사용자를 로그아웃 처리

  • 새로고침의 특성:

    • 새로고침은 페이지를 완전히 다시 로드하므로 JavaScript 메모리 상태가 초기화됨

    • 액세스 토큰은 메모리에서 관리되므로 새로고침 시 손실됨

    • 리프레시 토큰은 httpOnly 쿠키에 저장되어 유지됨

    • 클라이언트 측 보호 메커니즘(디바운싱 등)이 새로고침으로 초기화되어 효과가 없음

  • 동시성 처리 부재:

    • 현재 인증 시스템(백엔드)은 동일 사용자의 동시 토큰 갱신 요청을 적절히 처리하는 메커니즘이 없음

    • 연속적인 요청 간의 직렬화(순차 처리)가 이루어지지 않음

해결방법 후보:

  • 폐기 토큰 유예기간:

    폐기 후에도 1~2초 정도 유효시간을 설정해서 갱신을 가능토록 하는 방법. 탈락. 굳이 보안적 허점을 만들 필요가 없음. 현재 리프레시 토큰 로테이션 방식을 사용하는 의의도 무색해짐.

  • 토큰 버전 사용:

    현재도 토큰 버전은 사용하고 있으나 이는 사용자의 전체 기기 로그아웃, 또는 관리자의 강제 로그아웃 시 사용하므로 용도와 맞지 않음.

해결책:

세마포어 패턴을 사용하여 동일 사용자의 토큰 갱신 요청을 직렬화함으로써 문제를 해결.

물론 현재는 api서버에 대해서 단일 인스턴스로만 사용하기 때문에 가능함. 인스턴스가 늘어나게 된다면 별도의 서버가 필요할 수도 있음.

- 우선 현재는 트래픽이 거의 존재하지 않고, 또 연속 새로고침 시 서버가 401을 반환하면 로그아웃되므로 이 이슈는 후순위로 설정. 그러나 우선순위 기능 구현이 완료되면 반드시 이 문제부터 수정해야 함.(4월 초 예정)