본문 바로가기
개발 이론/Spring Security

[Spring Security] AccessToken과 RefreshToken

by dal_been 2023. 11. 26.
728x90

개인 프로젝트에 AccessToken이랑 RefreshToken을 아무 생각없이 도입하다 문득 생각이 들었다.

나는 왜 Refresh Token을 rdb에 저장했을까??

만약 로그아웃 했는데 AccessToken이 유효기간이 살아있는 채로 탈취당했다면 어쩌야하는 거지?? 

만약 RefreshToken 탈취는...??

 

아 기능 하나 중심으로 이렇게 많은 궁금증이 생기다니... 이거 찾다보니 2시간 뚝딱이었다. 나의 밑거름이 되리라 믿고 지금까지 찾아본 결과와 생각을 정리해본다

 

 

RefreshToken은 왜 도입했나??

 

나의 경우 JWT토큰을 accesstoken으로 하여 인증 인가 서비스를 구현했다. 토큰을 client에게 보내주면 클라이어트에서는 요청의 Authorization헤더에 토큰을 담아서 서버로 보내면 로그인한 회원을 확인하는 방식이었다.

 

여기서 Accesstoken은 보안상의 이유로 만료시간을 짧게 가져가게 하였다. 근데 만약 여기서 RefreshToken이 없다면 만료시간마다 토큰을 다시 발급하기 위해 로그인을 해야하는 문제가 생긴다.

 

그럼 그냥 만료시간 길게 하면 안되?? 앞서 말했듯이 보안상의 문제가 생긴다.

jwt토큰 자체가 stateless하다 -> 서버가 한번 발급한 토큰에 대해 제어권을 가지고 있지 않다.

따라서 만약 탈취 당한다면 서버 측에서는 토큰이 만료될때까지 기다리는 것 말고는 답이 없다.

 

이에 Refresh 토큰이 나온것이다.

 

AccessToken 유효기간 짧게, 자주 재발급하도록 하여 보안을 강화하면서도 다시 로그인 화면으로 가서 로그인하는 경우를 줄여주기!

-> 즉 RefreshToken은 AccessToken이 만료되었을때 새로 발급하기 위한 것

 

내 RefreshToken 형태

 

나의경우 UUID를 통해서 토큰을 만들었다.

 

근데 왜 JWT토큰으로 만들면 안될까?? 앞서 얘기했듯이 stateless하다. 즉 서버가 제어할 수 없는 것이다. 만약 RefreshToken이 탈취당한다면 토큰을 무효화할 수 있는 방법이 없다.

 


일단 간단하게 RefreshToken에 대해서 알아봣다. 이제 나의 물음에 답할 시간..

 

나는 왜 rdb를 이용했을까??

 

사실대로 얘기하자면 아무 생각이 없었다...

근데 token관련해서 찾아보니 redis즉 인메모리를 사용하는 것같았다. 생각해보면 Redis쪽이 조금더 나은 방향이라고 생각한다.

 

그이유는 일단 rdb에 저장한다고 생각하면...

필드에 분명 만료기간이 있을것이다. 그럼 만료가 되었을때 어째든 refreshtoken을 삭제하던가 못사용하게 조치를 취해야하는데 그럼 스케줄등을 이용해 주기적으로 만료된 토큰을 검사해야한다. 

또한 refreshtoken도 결국 주기적으로 삭제되고 새롭게 생성된다. 즉 영구적으로 저장될 필요가 없는 데이터이다.

 

근데 만약 redis를 사용한다면

인메모리 db방식으로 빠르게 접근 가능하고, 만료기간을 설정할 수 있다. 

그리고 만약에 서버가 다운되서 redis의 refreshtoken이 없어져도 사실 로그아웃정도의 경우이기때문에 큰 문제가 없다고 생각한다.

 

그래서 내가 생각하기에는 Redis를 이용하는게 좋은 방법인것같다. rdb를 사용하면 accesstoken이 만료될때마다 db에 접근해서 refreshtoken이 맞는지 확인하고 다시 재발급한다. 과연 db까지 갔다오고 만료될때마다 삭제하고 제거하는게 맞나..? 라는 생각이 든다.

 

결론은 Redis를 통해 db보다 빠르게 접근가능하게 하고 만료기간에 대해서는 redis가 알아서 할 수 있게 하면된다.

 

만약 로그아웃 했는데 AccessToken이 유효기간이 살아있는 채로 탈취당했다면 어쩌야하는 거지?? 

 

이부분도 찾아보니 블랙리스트라는 방법이 있다.

내가 걱정하는 부분은 로그아웃이후의 토큰의 살아있음이다. 그렇다면 로그아웃시 redis에 accesstoken 남은 유효기간만큼 저장하여 못사용하게 하는 것이다.

 

그니까 만약 블랙리스트에 accesstoken이 잇다면 요청을 거부하는 것이다.

 

여기서 플러스적으로 redis에 저장된 refresh token도 삭제해야한다.

 

 

만약 RefreshToken 탈취는...??

 

일단 위에까지 로그아웃하면 어느정도 보안이 조금 보충되었다. 

근데 로그아웃전에 RefreshToken탈취한다면...??

 

RTR방법이 있다. Refresh token을 한번만 사용할 수 있도록 하는 것이다. 

다시 말해 Refresh token을 사용해서 accesstoken을 발급할때마다 refresh token도 새롭게 발급하는 것이다. 

이렇게 하면 이미 사용된 refreshtoken을 검사하여 서비스 측에서 탈취를 관리할 수 있다.

 

다만 여기서도 만약 사용하지 않은 Refresh token을 탈취당한다면...?? 아 어렵다.. 그래서 클라이언트는 xss,crsf공격으로부터 refresh token이 탈취도지 않도록 안전하게 보관해야한다.

 

음 추가적인 탈취에 대한 보안 방법을 찾아보니 IP정보가 기기 정보를 토큰에 포함하는 방법도 있다고 한다.

탈취된 refreshtoken을 사용할때 다른 기기나 ip정보라면 요청을 거부할 수 있다.

 

 

 

 

위의 내용에 대해 조금더 자세하게 적어놧다 참고하시길...!
https://haebing.tistory.com/118