HTTP가 단순한 문서 공유를 넘어서 어플리케이션으로 발전하게 된다.
그 과정에서 서버가 클라이언트의 상태를 요구하는 상황이 발생하기 시작했다.
사용자 인증과 같은 경우가 가장 대표적이다.
앞서 언급한 HTTP의 비연결 성질을 해결하기 위해
초기에는 URL를 기반으로 상태를 전달했다.
그러나 해당 방식은 보안적으로 취약하여 해결책에 가까운 방법은 아니다.
https://matchuri.com/login?id=user1234&pw=1234
상태를 서버가 아닌 클라이언트 저장소에 저장하는 쿠키가 등장했다.
그러나 쿠키는 클라이언트 코드로 값을 수정이 가능하며 자바 스크립트로 쿠키 자체를 탈취하는 XXS 이슈, 자동 전송되는 특징을 악용한 공격인 CSRF 이슈가 존재했다.
또한, 매 요청마다 쿠키가 HTTP 헤더에 포함되기에 네트워크에 트래픽 낭비가 빌생한다.
다음으로 등장한 개념이 세션이다.
서버가 세션ID를 만든 후 해당 값과 매핑되는 정보를 세션에 저장한다.
그리고 서버는 세션ID를 클라이언트에게 전달한다.
브라우저는 이를 저장하고 요청시 세션ID를 헤더에 심어 서버로 전달한다.
이로 인해 중요한 정보를 노출시키지 않으면서도 쿠키값 변조도 무력화됐다.
그러나 이러한 세션에도 여전히 한계가 존재했다.
서버가 상태를 직접 관리하기에 다수의 서버가 존재할 경우에는 세션 정합성 문제가 발생했다.
이를 해결하기 위해 Sticky Session이나 Redis Clustering 방식으로 문제를 해결했지만 그로 인한 인프라 추가 비용 및 복잡도가 증가했다.
또한 사용자가 많아질 경우 서버에 세션 객체가 쌓이게 되기에 서버 메모리에 부담을 준다.
이러한 문제점을 해결하고자 JWT가 나왔다.
상태 관리를 다시 클라이언트로 돌리는 접근 방식이다. JWT 토큰 안에 정보를 담고 서버는 토큰의 서명만 검증하는 방식이다. 즉, 서버에서는 상태를 조회하지 않는다. 이러한 특징들로 인해 서버를 확장하는데 용이하며 쿠키를 주로 사용하지 않는 모바일 환경에서도 적합하다.
그러나 JWT 또한 한계점이 존재한다.
정보를 많이 담을수록 토큰이 길어지며 이는 쿠키와 마찬가지로 매 요청마다 전송하기에 네트워크에 트래픽이 낭비된다. 또한 토큰을 강제 만료할 수 없기에 토큰 자체가 탈취할 경우 해커가 만료할때까지 지속적으로 사용이 가능하다.
이러한 추가적인 문제점을 보완하기 위해서 엑세스 토큰과 리프레시 토큰을 동시에 운영하는 방식을 사용한다. 그러나 무상태를 지향하는 JWT에서 Refresh Token을 저장해야 된다는 모순적 구조가 발생하며 Refresh Token 자체가 탈취당할 경우에는 별개의 문제이다.
완벽한 기술은 없으며 JWT는 결국 세션의 확장성 문제만 해결한 셈이다.
중요한건 기술 자체가 아닌 맥락에 맞는 설계이다.