이 글은 JWT, 액세스 토큰, 리프레시 토큰 등에 대한 개념적 정리이다.
목차
1. 개선 이전 상황
2. 액세스 토큰, 리프레시 토큰 정리
3. 구현 내용
4. 자체적인 질문과 응답
1. 개선 이전 상황
나는 JWT를 통해 인증&인가 관련 기능을 구현하였었지만,
액세스 토큰과 리프레시 토큰을 구분하지 않고 만료시간이 일주일 정도로 긴 하나의 토큰만 사용중이였다.
이를 개선해 본다.
2. 액세스 토큰, 리프레시 토큰 정리
개선 이전의 내 방식은 어떤 문제가 있을까?
1. 토큰 만료일이 일주일로 매우 길다.
2. 토큰 탈취시 강제 만료시킬 방법이 없다.
사용자가 매번 로그인을 해야하는 불편함을 없애기 위해 만료시간을 길게 하였지만,
토큰을 탈취당하면 긴 시간동안 악의적 행동에 시달려야 하며, 만료일 전까지 이에 대처할 방법이 없다.
JWT를 서버에서 저장하고 있지 않기 때문이다.
이런 문제를 해결하기 위해 액세스 토큰, 리프레시 토큰 방식을 사용한다.
액세스 토큰
- 만료시간이 30분정도로 짧은 토큰. 인증을 위해 사용한다.
리프레시 토큰
- 만료시간이 1주일 정도로 긴 토큰. 액세스 토큰을 재발급하기 위해 사용한다.
- DB에 저장해서 클라이언트가 보낸 리프레시 토큰이 DB에 저장된 토큰과 일치하는지 대조한다.
3. 구현 내용
실행 흐름
내 서비스의 클라이언트와 서버의 통신 과정에서 상황별 실행 흐름을 정리했다.
1. 최초 로그인시
- ID, PW 입력해서 액세스 토큰, 리프레시 토큰 발급.
- 액세스 토큰은 매 HTTP request 마다 Authorization 헤더에 담아서 보낸다.
- 리프레시 토큰은 클라이언트에서 저장한다.
2. 액세스 토큰 유효
- 문제없이 HTTP resposne 받는다.
3. 액세스 토큰 만료
- 클라이언트는 401 status code 응답을 받는다
4. 액세스 토큰 만료, 리프레시 토큰 유효
- auth/reissue API 통해서 액세스 토큰, 리프레시 토큰을 재발급 받는다.
5. 액세스 토큰 만료, 리프레시 만료
- 클라이언트는 401 status code 응답을 받는다
- 사용자가 다시 로그인해야한다.
정기적으로 로그인 하는 사용자는 다시 로그인 할 일이 없다. 1주일 넘게 로그인 하지 않았다면 다시 로그인 해야한다.
Redis 적용
리프레시 토큰을 저장하기 위해 Redis를 이용하였다.
토큰을 저장하는 이유
- 토큰 탈취시 대처, 강제 로그아웃 등을 위한것
RDB가 아닌 Redis를 사용한이유
- 레디스는 특성 인메모리(RAM) 에 데이터를 저장하므로, 빠르다.
- 유효기간(TTL)을 데이터마다 지정할수 있다. RDB였으면 주기적으로 만료된 토큰을 지워줘야 했을것이다.
4. 자체적인 질문과 응답
4.1 클라이언트에서 액세스 토큰과 리프레시 토큰은 어디에 저장해야할까?
클라이언트가 브라우저라면
- refresh token 을 쿠키에 httpOnly 옵션, secure 옵션 등을 지정해 저장한다.
- local storage 에 저장하는것은 보안상 취약하여 XSS 공격받을수 있다.
클라이언트가 앱이라면
- IOS에서는 refresh token 을 keychain 이라는 안전한 저장소에 저장하고, userDefault 라는 보안이 취약한 곳은 이용해서는 안된다고 한다.
4.2 토큰의 탈취에는 어떻게 대처할까?
액세스 토큰
- 액세스 토큰은 서버에서 한번 발급한 뒤로는 제어할 방법이 없다.
- 그러나 토큰의 만료 시간이 짧기 때문에 긴시간 악용할수 없다.
리프레시 토큰
- 리프레시 토큰이 탈취된건 확인하면, 저장소의 리프레시 토큰을 삭제한다. 내 경우에는 Redis 내부의 데이터를 제거한다.
4.3 리프레시 토큰을 저장하면 세션과 차이가 없지않나? 왜 세션을 사용하지 않는가?
리프레시 토큰의 조회는 세션 조회보다 적게 일어난다.
내가 구현한 방식에서는, 액세스 토큰이 만료되었을때만 리프레시 토큰이 저장되어있는 저장소를(Redis) 조회한다. 세션 방식에서는 매 요청마다 조회할것이다. I/O 횟수가 크게 차이나므로 속도 측면에서 토큰 방식이 나을것이다.
브라우저, 애플리케이션 등에 모두 적용 가능하다.
앱에서는 쿠키,세션 방식을 잘 안쓴다.
이유는 앱은 설치되기 때문에, 파일 시스템 엑세스, 내부 DB 보유 등의 특징이 있어서 필요한 정보는 그냥 저장해서 필요할때 꺼내면 된다.쿠키와 세션 방식을 굳이 쓰자면 가능하지만, 그럴 필요가 없는것이다.
그래서 서버 개발시 쿠키,세션 방식과 토큰 방식 모두를 개발하기 보다 토큰방식을 선택해 사용하게 된다.
- 글을 마치며 -
100% 완벽한 보안에 집착하다 보면 생각이 자꾸 막히는것을 느꼈다.
막말로 누가 휴대폰을 뺏어가서 중요한 정보를 빼가는건 어쩔것인가? 어쩔수 없는 일이다.
최선을 다해서 HTTPS도 적용하고, 인증 흐름을 잘 설계하는것이 중요하다는 생각이 들었다.
그런 이유로 조사과정에서 JWT에 대한 대안으로 PASETO 라는것도 있다라는 내용을 찾았지만, 필요한 순간이되면 다시 찾기로 하였다.
출처:
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#refresh-token
https://www.quora.com/Why-are-there-no-cookies-for-the-mobile-web-or-apps
https://jinyoungchoi95.tistory.com/m/39
'Dev > 개발일지' 카테고리의 다른 글
서버에 HTTPS 적용하기 (0) | 2022.12.05 |
---|---|
테스트 코드 리팩토링 해보자 (0) | 2021.11.20 |
DB 구조 변경과 데이터 옮기기 (0) | 2021.11.16 |
AWS beanstalk에서 RDS 사용하려고 삽질 (0) | 2021.11.06 |
스프링 데이터 JPA, Query DSL 완강 (0) | 2021.07.05 |