Spring JWT: Access Token과 Refresh Token

·2022년 11월 2일
2

Spring

목록 보기
8/8

서론

지금까지의 프로젝트에서 JWT를 활용하여 사용자를 인증해 사용해왔지만, Access Token과 Refresh Token에 대해 제대로 된 이해와 고민 없이 단순히 구현에만 치중한 것 같아 관련 내용을 정리해보려 한다.

JWT를 활용한 토큰으로 사용자의 정보와 토큰의 암호화 키, 해시 알고리즘, 토큰의 만료시간 등 인증과 유효성 검증을 위한 정보가 담겨 있다.

이 토큰을 클라이언트가 헤더에 담아 요청하면 서버는 유효성을 검증하고, 클라이언트의 권한을 판별해 요청을 반환한다.

지금까지는 개발자와 이용자의 편의성을 고려해 유효시간을 길게 설정해 이용해왔지만 이는 토큰이 탈취 당할 경우를 무시한, 보안을 고려하지 않은 개발이다.

이를 보완하기 위해 Access Token과 Refresh Token을 활용하여 보안과 편의성을 최대한 지킬 수 있는 방안을 찾아보았다.


본론

Access Token과 Refresh Token의 유효시간

  • 클라이언트가 로그인을 하면 짧은 유효시간의 Access Token과 상대적으로 긴 유효시간의 Refresh Token을 발급한다.

Access Token을 클라이언트가 Header에 담아 전송할 때, 공격자에게 탈취 당하더라도 짧은 유효시간을 설정해둔다면 비교적 피해를 줄일 수 있다.
하지만 Access Token의 유효시간을 줄이면 사용자는 잦은 로그인으로 불편함을 겪는다.

이런 불편함을 해소하기 위해 Refresh Token을 활용한다.

Refresh Token의 존재 이유

  • Refresh Token은 Access Token의 갱신을 위해 사용한다.

클라이언트가 서버에 어떤 요청을 하기 전, 기존에 가지고 있던 Access Token이 만료되었다면, Refresh Token을 통해 Access Token의 갱신을 요청하고 새로운 Access Token을 이용해 요청을 보낸다. 그렇기 때문에 Refresh Token은 Access Token보다 긴 유효시간을 가져야 한다.

Token이 탈취된 경우

  • Refresh Token이 탈취 당하는 경우를 판별할 수 있다.

기존의 Access Token이 만료되지 않았는데 Refresh Token을 이용해 갱신을 요청한다면, 이는 비정상적인 접근이라고 판단하고 기존의 Access Token과 Refresh Token을 모두 폐기해버린다.
여기서 폐기란 폐기하려는 토큰을 데이터베이스에 보관하여 Ban을 하는 것이다. 빠른 조회를 위해 Redis와 같은 비관계형 데이터베이스에 보관하며, 저장에 필요한 용량을 줄이기 위해 Refresh Token의 만료시기까지만 보관하여 불필요한 토큰을 저장하지 않도록 한다.

Token 저장 방식

  • Access Token과 Refresh Token은 별개로 보관한다.

주로 클라이언트는 Access Token을 Local Storage나 Session Storage에 보관한다.
두 토큰이 모두 탈취 당하는 경우를 방지하기 위해, Refresh Token은 HTTP-ONLY 속성이 부여된 Cookie에 저장하는 것을 권장한다고 한다.
일부의 경우, State에 보관하거나 변수에 담아 보관한다고도 했으니 정답은 없는 것 같다.

서버와 클라이언트에서의 동작 방식

최종적인 동작 방식을 정리하면 다음과 같다.

서버에서의 동작

  • 클라이언트 로그인시, Access Token과 Refresh Token을 함께 발급해주고 사용자에게 매핑해 DB에 저장해둔다.
  • 클라이언트 로그아웃시, Access Token과 Refresh Token을 폐기한다.
  • 서버는 각 요청의 헤더에 토큰이 들어오면 Banned Token 여부를 확인하고, 토큰의 유효성을 확인해 요청에 응답한다.
  • Refresh Token을 이용한 Access Token 갱신 요청이 오면 DB에 매핑된 Access Token의 만료 여부를 확인해보고, 아직 만료되지 않은 Access Token의 갱신 요청이라면 비정상적 접근으로 판단해 둘 다 폐기한다.

클라이언트에서의 동작

  • 로그인을 하며, Access Token과 Refresh Token을 받아 별개의 스토리지에 보관한다.
  • Access Token을 요구하는 요청을 보낼 때에는 Access Token의 만료 여부를 확인한 후, Header에 토큰을 담아 전송한다.
  • 만료 여부 확인시, 이미 만료된 Access Token이라면 Refresh Token을 이용해 재발급을 요청하고 스토리지에 갱신한다.

결론

여러 자료를 찾아본 후, 나는 이 동작 방식이 가장 합리적인 방식이라고 생각하지만, 개발자나 어플리케이션에 따라 토큰의 이용방식이 다를 수 있고 정답은 없는 것 같다.

profile
SSAFY 7기

0개의 댓글