개인 프로젝트에 JWT 기반 인증 시스템을 도입했었는데,
일단 실습을 해보는 것에 목적이 있어 대략의 조사만 거친 뒤 바로 실제 구현에 착수했었다.
이미 구현이 완료된 시점이지만,
JWT 기반 인증을 도입하기 위해 필요했던 기술적인 검토를 늦게나마 충분히 해보려고 한다.
일단,
왜 다른 옵션을 제쳐두고 JWT를 사용해 인증 시스템을 구축해야 하는지 충분한 근거가 필요하겠다.
먼저 JWT 기반 인증을 포괄하는 한 단계 위의 어젠다인 토큰 기반 인증에 대해 알아보자.
JWT 기반 인증 시스템을 도입한다는 건,
토큰 기반 인증을 도입하겠다는 것이고 그 과정에 사용할 토큰으로 여러 유형 중 JWT를 선택하겠다는 뜻이다.
그러니 토큰 기반 인증의 도입 근거부터 먼저 확립해보자.
토큰 기반 인증은
기존의 세션 기반 인증 방식의 대안 격으로 많이 채택되고 있는 인증 방식이다.
기존의 세션 기반 인증이라고 함은,
유저에게 보여줄 컨텐츠, 데이터 등을 관리하는 서버 측에서 유저의 로그인 여부를 인증하는 세션을 생성하고 유지하며 유저의 요청을 인증하는 방식을 말한다.
보다 구체적으로는 다음과 같은 시나리오에 따라 유저 인증이 일어난다.
⏳ 세션 기반 인증 시나리오
- 클라이언트에서 서버로 유저가 로그인 요청
- 로그인 성공 시 서버는 세션 생성 후 메모리/DB에 저장
- 생성된 세션의 ID를 쿠키에 담아 클라이언트에게 로그인 응답
- 이후 클라이언트 측은 매번 세션 ID가 쿠키에 담긴 요청을 보내게 됨
- 서버는 요청 쿠키에 담긴 세션 ID를 저장 중인 세션들과 대조해 유저 인증
여기서 가장 중요한 건 세션을 서버가 생성 후 저장해서 갖고 있는다는 점이고,
이전 요청으로부터 비롯된 유저의 인증 상태(state)가 세션의 형태로 유지되면서 이후 요청에 계속 영향을 미치기 때문에 stateful한 서버를 요구하는 인증 방식이다.
서버의 stateful한 특성을 중심으로 다음과 같은 장단점을 갖는다.
기존 세션 기반 인증 방식의 문제점은 결국 서버의 stateful한 특성에서 비롯되는데,
그 반대 특성인 토큰 기반 인증의 stateless함을 활용하면 이에 대한 대안을 마련할 수 있다.
토큰 기반 인증은
는 기본 골자는 세션 기반 인증과 비슷하지만,
결정적으로 서버에서 유저의 인증 상태를 따로 저장해 보관하지 않는다는 점에서 다르고,
따라서 서버가 매 요청을 그 자체로 독립적으로 처리할 수 있기에 stateless하다.
보다 구체적인 인증 시나리오는 다음과 같다.
🪙 토큰 기반 인증 시나리오
- 클라이언트에서 서버로 유저가 로그인 요청
- 로그인 성공 시 서버는 서명된 토큰을 발급해 응답 payload에 담아 유저에게 전달
- 이후 클라이언트 측은 토큰을 저장해두고 매번 헤더에 담아 요청
- 서버는 요청 헤더에 담긴 토큰을 검증해 유저의 요청을 인증
발급 받은 토큰을 클라이언트 측에서 저장하기 때문에
인증 정보 관리의 책임이 서버에서 클라이언트 쪽으로 옮겨간 것으로 이해를 할 수도 있겠다.
이처럼 세션 인증과 대조되는 특성으로 인해 다음과 같이 반대되는 장단점을 갖는다.
정리하자면,
두 방식 모두 HTTP 요청 자체의 stateless함을 극복하고 인증 상태(state)를 유지하기 위한 방법이라는 동일한 출발점을 갖고 있다.
그리고 서버 측에서 인증에 필요한 정보를 건네주면 클라이언트가 이후 요청마다 이 정보를 담아 전송한다는 기본 골자도 비슷하다.
다만,
세션 기반 인증은
토큰 기반 방식은
두 방식 모두 장단이 있지만,
웹 서비스들이 복잡해지고 커지면서
세션 기반의 안전성보단 토큰 기반 인증의 확장성이 선호되는 경우가 많아지면서 토큰 기반 인증 방식이 많이 채택되고 있는 흐름이다.
self-contained vs. reference 토큰
후에 설명할 JWT의 내부 구조를 보면 알겠지만,
JWT는 인증에 사용되는 정보가 토큰 안에 들어 있어 self-contained한 토큰이다.반면 reference 토큰은 어딘가 다른 곳에 저장되어 있는 진짜 토큰에 대한 식별자로서 기능한다. 세션 ID 역시 일종의 reference 토큰이라고 볼 수 있겠다.
그리고 MSA 아키텍쳐의 분산 구조에선,
마이크로서비스가 직접 받아 토큰을 검증하기만 하면
별도의 추가 절차 없이 그 안에 있는 정보만으로 인증이 완료될 수 있는 self-contained 토큰이 마이크로서비스 각각의 독립성을 보장할 수 있다는 점에서 선호된다.
위와 같은 검토를 거쳐 세션 기반 인증 대신에 토큰 기반 인증을 채택했다면,
이제 JWT가 다른 토큰들에 비해 갖는 이점이 무엇인지를 짚고 넘어가보자.
먼저 SAML(Security Assertion Markup Language)과 비교하면 JWT의 내용이 훨씬 컴팩트하고 인코딩 이후 크기도 작다. 따라서 HTTP 통신으로 주고 받기에 더 유리하다.
그리고 SWT(Simple Web Token)가 서명에 HMAC 알고리즘만을 지원하는 데 반해 JWT는 토큰의 출처까지 보장할 수 있는 RSA 알고리즘을 추가로 지원한다.
또 SAML을 사용하기 위해 디지털 서명 방식으로 XML을 안전하게 서명하는 것이 JWT를 서명하는 것보다 훨씬 까다롭다. 결국 보안 측면에서 이점이 있다.
마지막으로 JWT는 웹 표준(RFC 7519)으로 지정되어 있고, 대부분의 프로그래밍 언어에서 JSON 구조가 네이티브 객체로 바로 매핑이 되기 때문에 parser 지원이 빵빵한 반면 XML은 그렇지 않다. 이런 호환성 측면에서 JWT를 활용한 작업이 용이한 점이 있다.
이런 여러 이점이 있지만
결국 마지막 이점과도 같은 맥락에서, JWT가 요즘의 웹 앱, 모바일 앱으로부터의 서버 접근 상황 시나리오에서 일종의 인증 표준으로 통용되고 있다는 사실에서 오는 이점이 크다. 많은 서비스의 사용 사례가 이미 쌓여 있고 이를 중심으로 생태계 내의 다양한 지원을 기대해볼 수 있다.
그래서 결론,
여러 토큰 중 JWT를 선택하는 것은 충분히 합리적인 결정.
지금까지 JWT 기반 인증을 도입할 근거에 대해 꼼꼼히 검토를 해봤으니, 이제 기술에 대해 확실히 알고 사용할 차례다.
다음 글에선 JWT 안에는 어떤 내용이 들어있는지, 서명이란 무엇인지, JWT의 구조에 대한 내용을 다뤄보겠다.