최종 변경 : 2024.01.16
주관적으로 제가 했었던 생각을 공유하고자 작성한 글입니다. 개발 자체가 모든 방향에서 항상 정답일 수 없듯이 잘 이해해서 들어주시길 바랍니다.
JWT 공부를 시작했을 때 JWT를 왜 사용하는지를 잊어버려 한동안 고민에 잠겼고 결론을 찾아 헤매었던 적이 있습니다. 그 고민의 흐름과 주관적인 결론을 남깁니다.
JWT의 STATELESS 상태에 대한 집착
시큐리티 JWT config를 구성하며 STATELESS 상태에 초점이 맞추어졌습니다.
(JWT 구현을 위해 STATELESS 상태가 필요하지만 STATELESS에 집착해야 하는건 아닙니다. 따라서 여기서 포인트 자체를 놓쳤습니다. 아무튼 이 과정을 작성하며 STATELESS 상태에 광적으로 집착을 하였습니다.)
토큰 탈취의 문제 - Refresh 토큰의 도입과 Refresh 토큰도 동일한 상황
이때 부터 의문 사항이 생기게 되는 시발점입니다. JWT 자체가 세션 대비 토큰을 탈취 당했을때의 위험성이 큽니다.
따라서 Refresh, Access라는 2가지의 토큰을 발급해주는데 Refresh 토큰 요청 주기 자체가 길기 때문에 탈취 당할 확률은 낮지만 탈취 당할 수 있다 입니다.
이제 이 문제에 대한 여러 상황이 발생합니다.
토큰이 탈취 되었을때 서버의 제어권과 로그아웃 문제 등등
토큰이 탈취되면 만료 기간 까지 서버측은 고통을 받습니다. 따라서 서버 비밀키를 변경하는 상황까지 도달하게 됩니다.
프론트 서버측 로그아웃을 구현하여도 이미 토큰을 복제 했다면 계속 서버에 접속할 수 있기 때문에 여전히 문제가 있습니다.
이를 위해 서버측 Redis와 같은 저장소에 발급한 Refresh 토큰을 저장한다는 구현들이 많았습니다. 그래서 로그아웃 상태거나 탈취된 토큰은 Redis 서버에서 제거하여 앞으로 Access 토큰 재발급이 불가능하도록 설정하는 것이었습니다.
깊은 고민의 발생 - 모순?
Refresh들을 저장하기 위한 Redis를 도입해버리면 사실상 세션 클러스터링을 작업하고 세션 방식을 사용하는 것이 좋지 않을까? STATELESS 작업을 했지만 다른 곳에서 상태 저장이 생겨버리네? (사실 엄밀하게는 아니지만 비슷한 맥락으로)
아무튼 여기까지해서 많은 고민을 했고 탈취를 막으면서도 Redis를 도입하지 않을 방법에 대해서 한가지 방법을 떠올렸습니다.
IP 검증을 해보자 - 실패
처음 로그인이 요청된 IP를 JWT에 담아 매번 요청이 올때마다 JWT의 IP와 요청 IP가 동일한지 검증을 진행하는 방법을 구상했는데 사용자들의 단말기는 IP값이 동적으로 자주 변경되기 때문에 문제가 되어 실패했습니다.
그래서 고민의 굴레에 빠졌습니다.
STATELESS → 그런데 Redis → 그럼 차라리 세션 → 왜 JWT를 사용했지?