서버에서 사용자 인증 후 인가를 하는 방식은 크게 두가지가 있다.
첫번째는 전통적으로 가장 많이 쓰이는 방식인 Session
을 사용하는 방식이고 두번째는 토큰을 발급하는 방식이다. 최근에는 매우 큰 수의 사용자들에게 실시간으로 제공되는 서비스가 많아지면서, 서버에 부담이 적은 방식인 JWT
를 많이 사용한다.
그렇다면 Session
을 사용하는 방식과 JWT
를 사용하는 방식의 차이는 무엇일까?
우선 Session
이라는 것은 서버측에서 메모리에 데이터를 저장해두는 방식이다. 사용자가 인증에 성공하면 사용자의 정보를 서버의 메모리(Session
)에 저장해두고 사용자에게 해당 session
의 식별자(JSESSIONID
)를 발급한다. 이 식별자는 http-only
쿠키로 사용자의 브라우저에 저장되고 이후 요청을 보낼 때마다 쿠키에 저장된 식별자를 통해 세션에 저장된 사용자 정보를 불러오게 된다.
이러한 방식을 서버가 사용자의 정보(상태/state)를 지속해서 가지고 있다는 의미로
stateful
하다고 한다.
이 방식은 한눈에 보이듯 사용자가 많아질수록 서버에 가해지는 부담에 매우 커진다. 사용자가 로그아웃을 하지않은 상태로 브라우저를 종료할 경우 서버측에서는 이를 알 방법이 없다. 그러므로 비용을 줄이기 위해 session
을 사용할 때는 반드시 만료시간을 설정해둬야 한다.
반면 JWT
는 사용자가 본인의 정보를 가지고 있고 요청을 보낼 때마다 본인의 정보를 함께 보내는 방식이다. 사용자의 개인정보를 여기저기 계속 보낸다는 것은 당연히 매우매우 매우 위험한 방식이다. 그러므로 서버에서는 이 정보를 암호화 해서 보낸다.
이러한 방식을 서버가 사용자의 정보(상태/state)를 가지고 있지 않다는 의미로
stateless
하다고 한다.
JWT
를 사용하면 서버측에서 인가된 사용자 정보를 메모리에 저장해 둘 필요가 없어서 부담이 훨씬 줄어든다. 하지만 사용자의 개인정보 탈취 위험이 있을 수 있다. 그러므로 JWT
를 사용할 때는 암호화에 사용되는 Secret key
관리가 아무리 강조해도 부족할 정도로 중요하다.
그래서 사용하는 것이 Key Rolling
이다. 쉽게 말하면 Key Rolling
은 Secret key
를 여러개 사용하고 자주 교체해주는 것이다. 이 때 여러개의 Secret key
중 하나에 Unique한 ID (kid
혹은 key id
라고 부른다)를 연결시켜 둔다.
이후 JWT
토큰을 만들 때 헤더에 kid
를 포함하여 제공하고 서버에서 토큰을 해석할 때 kid
로 Secret Key
를 찾아서 검증한다.
서버의 부담을 줄여주는 것 외에도 JWT
는 많은 장점이 있다. 첫번째로 복잡한 서버세팅의 필요성을 줄여준다.
사용자가 많아져 서버에 가해지는 부담이 클 경우에 L4 스위치
를 활용해 로드밸런싱을 하게 된다.
로드 밸런싱이란 말 그대로 같은 역할을 하는 서버를 여러대 둠으로써 서버에 가해지는 부담을 줄여주는 것인데, 만약 서버 A, 서버 B 가 있다고 할 때, A 서버에서 인증을 받은 사용자의 정보는 B 서버에서는 인증 정보가 없을 것이다.
이 문제를 해결하기 위해 세션 클러스터링 작업을 하게 된다. 이 작업을 통해 분산되어 있는 서버의 세션을 동기화 시켜 하나의 서버처럼 작동하도록 하는 작업이다.
근데 만약 JWT
를 사용한다면? 모든 서버에서 JWT
를 복호화 함으로써 같은 정보를 공유하게 된다. (물론 인증 외에도 세션을 사용한다면 클러스터링은 해야할 것이다.)
또한, 최근 네이버, 카카오, 구글 등 서비스에서 제공하는 인증 서비스 또는 SSO 서비스를 개발 또는 사용한다.
암호화된 토큰 형태이기 때문에 Secret Key
관리만 잘한다면 제 3자에게 발급해주고 제 3자에서 필요에따라 토큰과 함께 요청을 보내면 검증 후 응답해주는 절차도 간단한 편이다.