이 글은 효율적인 JWT 재발급 프로세스에 대해 고민하고 개선하는 과정을 다룬다.
🌱 들어가기 전
많은 서비스에서 인증/인가를 위해 JWT를 사용하고, 보안상 만료시간을 설정한다. 따라서 JWT 만료시 이를 재발급하는 프로세스가 필수적이다.
🌱 상황
작업중인 Seat Sense 서비스에 인증/인가를 위해 JWT를 도입했다.
기존에는 'JWT 재발급 API'를 구현하여, 토큰 만료시 클라이언트에서 다시 JWT 재발급 API를 요청하도록 구현하였다.
💭 고민사항
특정 조건에서 동작하는 JWT 재발급 프로세스가 반복적인 작업으로 느껴졌다.
"반복되는 작업을 자동화하여 효율적인 프로세스로 개선할 수 없을까?" 고민했다.
🌱개선사항
필수적으로 동작하는 로직은 해당 로직 실행을 위한 조건이 충족됐을 때 자동으로 실행되도록 구현을 개선할 수 있었다.
즉, JWT 만료 여부를 체크하고 만료시 클라이언트에서 JWT 재발급 API를 다시 요청하게 구현하는게 아니라, 서버는 요청받은 기능 API의 응답을 그대로 돌려주되 토큰도 재발급하여 함께 응답하도록 구현을 개선했다.
💭 이외에 신경 쓴 사항
<Refresh Token과 Refresh Token을 저장하는 Cookie>
- Cookie에 HttpOnly 속성을 적용해, JavaScript에서 쿠키에 접근하지 못하도록 하여 XSS 공격에 대비했다.
- Cookie에 Secure 속성을 적용해, HTTPS 통신에서만 쿠키가 전송되도록하여 쿠키 탈취시에도 쿠키에 담긴 정보를 알아낼 수 없도록 했다.
- RTR(Refresh Token Rotation)기법을 적용해 중간에서 토큰을 탈취하여 사용자를 도용하는 경우를 대비했다.
- Access Token의 유효기간을 더 짧게 만들어 보안에 더 신경썼다.
🌱 시나리오
해당 과정을 시나리오로 살펴본다.
🌱 AS-IS
1. 클라이언트 ➩ 서버
기능 API에 요청을 보낸다. 서버는 Access Token의 유효성을 검사한다. 토큰이 만료된 상태이다.
2. 서버 ➩ 클라이언트
서버는 만료된 Access Token이라고 401(Unauthorization)를 반환한다.
3. 클라이언트 ➩ 서버
JWT 재발급 API로 요청을 보낸다.
4. 서버 ➩ 클라이언트
Refresh Token 검증 후 유효하다면, Access Token을 재발급해준다.
5. 클라이언트 ➩ 서버
재발급받은 Access Token으로 기존에 요청하였던 기능 API에 다시 요청을 보낸다.
6. 서버 ➩ 클라이언트
서버는 Access Token 유효성을 검사한다. 토큰이 유효하다. 요청받은 기능 API에 대해 응답한다.
🌱 TO-BE
1. 클라이언트 ➩ 서버
기능 API에 요청을 보낸다. 서버는 Access Token의 유효성을 검사한다. 토큰이 만료된 상태이다.
서버는 쿠키에 담긴 Refresh Token을 검증하고, 유효하다면 Access Token과 Refresh Token을 재발급한다.
2. 서버 ➩ 클라이언트
재발급 한 Access Token과 요청받은 기능 API의 응답을 함께 보낸다.
🌱 결론
JWT 재발급과 관련한 프로세스의 네트워크 I/O를 6번에서 2번으로 감소시켰다.
🌱 아쉬운 점
"개선한 방식이 토큰의 사용 목적에 정말 적절할까? 보완해야 할 부분이 있지않을까?" 에 대해 계속 생각해봤다.
토큰은 탈취와 악용에 대한 보안이 정말 중요하다.
그런 관점에서 토큰 만료시 자동으로 재발급되는 프로세스는 지속적인 악용 가능성이 존재한다는 생각이 들었다. 즉, Access Token 만료시에도 해커는 새로 발급된 Access Token을 사용해 계속해서 API를 호출할 수 있게 되는것이다.
현재 Access Token은 헤더에 재발급하기 때문에, 해커가 새로운 토큰을 헤더에 포함시키려면 클라이언트 코드 로직에 침투하여 토큰 갱신 과정을 가로채는 등의 해킹방식이 필요할 것이다. 따라서 해커가 재발급된 토큰을 자동으로 인지하고 사용할 가능성은 낮다고 생각된다. 하지만 자동화 한 프로세스인만큼 보안을 더 강화하는게 좋을 것 같다.
💭 문제 상황 시나리오
해커가 헤더에 재발급 되는 토큰을 자동으로 인지하고, 클라이언트의 토큰 갱신 과정을 가로채고 있다고 가정해보자.
그리고 해커가 사용자A의 토큰을 탈취해서 악용하고있다고 가정해보자.
1. 2024.08.08 19:00에 Access Token 만료
2. 2024.08.08 19:01에 해커가 기능 API 요청보냄
3. 2024.08.08 19:02에 사용자A가 기능 API로 요청보냄
개선과정(TO-BE)에서 보안을 위해 Refresh Token에 RTR방식을 적용했던 것을 생각해보면, Refresh Token에 사용횟수 제한이 걸려있기 때문에 3번 과정에서 서버는 사용자A에게 유효하지않은 토큰이라는 예외를 던질것이다. 그리고 해커는 계속해서 재발급받은 토큰을 악용할 것이다.
💭 해결방안
- 이미 한 번 사용된 Refresh Token으로 또 토큰을 재발급 하려는 상황이 발생하면, 그에 따른 해당 계정 로그아웃 및 관련 토큰 무효화 조치를 수행한다.
위 조치를 통해 해커가 토큰을 악용할 수 있는 가능성을 더 낮출 수 있을 것이다.
'프로젝트' 카테고리의 다른 글
[프로젝트-Redis] 다중 서버 환경에서 락 동기화 문제 해결을 위한 Redisson 분산 락 도입 (1) | 2024.10.19 |
---|---|
[프로젝트 - 트러블 슈팅] 동시성 제어의 트랜잭션 이슈 및 테스트 환경 이슈 해결 (1) | 2024.09.18 |
[프로젝트] 네임드락을 통한 의자 예약 기능의 동시성 문제 해결 (0) | 2024.04.14 |
[프로젝트] 대량 트래픽에 대한 조회 성능 개선 (쿼리 최적화 및 캐시) (0) | 2024.03.17 |