Categories
일상

JWT 혹은 OAuth2 의 refresh 토큰을 어디다 저장해야 할까?

요즘 네이버로그인, 카카오 로그인이나 구글 로그인등등 소셜 미디어(Social media) 사용자 로그인 처리를 하다보니 로그인된 상태가 끊임없이 유지되는 것을 구현해야 되더군요. 그러려면 결국 리프래시 토큰(refresh token)을 어디에 저장해 둬야하나 하는 문제로 골머리를 앓게 됩니다.

접속 토큰(access token) 은 만료시간이 짧기 때문에 좀더 오픈된 공간에 저장해도 되지만.. 리프래시 토큰은 그러기가 쉽지 않습니다.

웹에서 사용자의 로그인 정보를 범용적으로 저장할만한 공간은 클라이언트 사이드에서는 로컬스토리지(Localstorage), 쿠키(Cookie) 등이 있습니다. 서버 사이드에서는 대표적으로 세션(Session)이나 Database 등에 저장할 수 있겠죠.

과연 어느 장소에 저장해야 할까요? ^^;

1. Local Storage

처음에는 local storage 나 쿠키(Cookie)에 저장하는 방법을 생각해 보았는데요. local storage 는 자바스크립트로 접근이 너무 쉬워서 XSS 공격에 취약하고 보안상 문제 소지가 많아 보입니다.

2. 쿠키 (Cookie)

쿠키의 경우는 HTTPOnly 와 Secure 옵션을 사용하고 CSRF 공격에 대비를 하면 어느정도 보안이 되기때문에 한때는 여기다가 리프레시 토큰을 저장하곤 했습니다.

하지만 쿠키도 역시 불안하기는 마찬가지라서 좀 더 좋은 방법이 없나 궁리를 해보게 되는데요.

3. 결국은 Server Side

역시 가장 좋은 방법은 서버사이드에 저장해두는 것이겠죠.

가장 간단한 방법은 세션에 저장하고 세션 만료 주기를 왕창 늘려주는 방법도 있는데요. 이건 사용자가 얼마 안된다면 써먹어 볼 수 있겠지만 역시 사용자가 많은 경우에는 말도 안돼는 방식이고… 애초에 세션을 사용하지 않으려고 만든게 액세스 토큰 방식인데 뭔가 아닌거 같더라고요.

그래서 생각해 낸 것이 DB 에 저장하는 방법입니다.

DB에 실제 리프레시 토큰값을 저장하고 이때 index 값을 쿠키나 로컬스토리지에 저장하는 방법입니다. 쿠키에 저장하는 경우 만료기간을 한달이나 1년등으로 길게 잡으면 충분히 끊임없이 로그인 된 상태를 유지할 수 있습니다.

이렇게 하면 리프레시 토큰값은 노출시키지 않고 크게 의미없는 index 값 만 노출되므로 보안상 좀 더 안전하게 저장할 수 있습니다. 게다가 저장하는 인덱스값도 유추가 쉬운 단순 순번값보다는 hash값을 생성해 사용하면 보안에 더욱 유리할 것입니다.

이렇게 되면 결론적으로 리프레시 토큰값에 대한 해시테이블(hash table) 혹은 해시맵(hash map)을 구현하게 됩니다.

참고로 카카오 개발자 페이지에서 카카오 로그인 Javascript 문서중 refresh token 관련 된 정보(아래 링크의 페이지 맨 하단에 있습니다.)를 봐도 클아이언트 단에서 refresh token 을 노출하지 않도록 REST API 로만 처리할 수 있도록 정책이 바뀌고 있는 것을 확인할 수 있습니다.

https://developers.kakao.com/docs/latest/ko/kakaologin/js#advanced-guide

만료기간이 짧은 access token 의 경우에는 저장 위치를 클아이언트단에서도 할 수 있지만 아무래도 만료기간이 긴 refresh token 의 경우 탈취된다면 크게 문제가 될 수 있기 때문이라고 생각됩니다. refresh token 은 가능한한 쉽게 접근할 수 없는 곳에 저장하는 것이 정답인듯 합니다. ^^

참고자료

https://velog.io/@ehdrms2034/Access-Token-%EC%A0%80%EC%9E%A5-%EC%9C%84%EC%B9%98%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0