개발자
[JWT]JWT를 왜 쓰는걸까?/토큰과 세션방식의 차이점 본문
[JWT]JWT를 왜 쓰는걸까?/토큰과 세션방식의 차이점
GoGo개발 2023. 7. 13. 18:38저는 이번 프로젝트를 JWT 방식을 사용해서 진행했습니다. 그렇다면 왜 JWT를 적용했는지 알아봐야겠죠.
JWT는 토큰 기반 인증입니다. 토큰 자체에 사용자의 권한 정보나 서비스를 사용하기 위한 정보가 포함됩니다.
JWT가 등장하기 전에는 웹에서 쿠키(cookie)와 세션(session)을 이용한 사용자 인증을 구현하는 경우가 많았는데요. JWT는 어떤 장점이 있어 많이들 사용하는 걸까요? 아마도 가장 큰 이유는 확장성에 있을 것 같은데요. JWT는 토큰 자체에 사용자의 정보가 저장되어 있어있기 때문에 서버 입장에서 토큰을 검증만 해주면 됩니다. JWT와 같은 토큰을 클라이언트에 저장하고 요청시 HTTP 헤더에 토큰을 첨부하는 것만으로도 단순하게 데이터를 요청하고 응답을 받아올 수 있게 되는 겁니다.
다른말로 RESTful과 같은 무상태(Stateless)인 환경에서 사용자 데이터를 주고받을 수 있게 되는 건데요. Stateless란 클라이언트와 서버 관계에서 서버가 클라이언트의 상태를 보존하지 않음을 의미합니다. 서버의 확장성이 높기 때문에 대량의 트래픽 발생 시에도 대처를 수월하게 할 수 있게됩니다.
반면에 쿠키와 세션을 사용할 때는 서버 단에 로그인한 모든 사용자의 세션을 DB나 캐시(cache)에 저장해놓고 쿠키로 넘어온 세션 ID로 사용자 데이터를 매번 조회해야만 하죠.
따라서 JWT를 사용할 때는 사용자가 늘어나더라도 사용자 인증을 위해서 추가로 투자해야하는 인프라 비용을 크게 절감할 수 있습니다.
뿐만 아니라 쿠키를 사용하지 않으므로 CORS 문제에서 자유로워진다는 것도 장점으로 여겨질 수 있겠습니다.
요약하자면 가장 큰 차이점은세션은 데이터베이스 서버에 저장된다는 것, 토큰은 클라이언트 측에서만 저장한다는 점입니다.
토큰과 세션을 간단하게 알아보았지만 차이점을 더 자세히 알아보겠습니다.
http의 비상태성(Stateless)
이 전의 스프링 시큐리티에서 인증과 인가를 다루었었는데요, 간단하게 말하자면 인증은 사용자가 맞는지를 검증하는 과정이고 인가는 인증된 사용자에 대한 자원에 대한 접근 확인 절차를 의미합니다. 이를 기억하고 http에 대한 설명을 들어가겠습니다.
바로 직전의 통신도 기억 못하는 HTTP
HTTP는 비상태성이라는 특성을 갖습니다. 위에 설명했듯이 서버는 클라이언트의 상태를 저장하지 않으며, 따라서 이전 요청과 다음 요청의 맥락이 이어지지 않습니다. HTTP는 바로 직전에 발생한 통신을 기억하지 못하기 때문에 HTTP 단독으로는 요청한 클라이언트가 이전에 이미 인증과정을 거쳤는지 알 방법이 없습니다.
그렇다고, 글을 조회하거나 작성할 때 마다 사용자에게 로그인을 하라고 요청할 수는 없는 노릇입니다. 매 작업마다 로그인을 사용자에게 요청하는 것은 UX를 전혀 고려하지 않은 방식입니다.
그렇다면, 사용자의 아이디와 패스워드를 브라우저에 그대로 저장해놓고, 매 요청마다 함께 그 정보를 보내는 방법은 어떨까요? 이런 방식은 전송 데이터가 커져 비효율적일 뿐더러 클라이언트에 민감한 데이터가 그대로 저장되어 보안에도 굉장히 취약합니다. 서버 입장에서도 매 작업마다 데이터베이스를 조회하고, 인증과정을 거치는 것이 비효율일 것 입니다.
이런 HTTP 환경에서 서버는 어떤 방식으로 사용자를 인가할까? 웹 어플리케이션에서는 이 문제를 세션 또는 토큰을 사용하여 문제를 해결합니다. 즉, 세션과 토큰은 인증 보다는 인가와 관련된 기술이라고 할 수 있습니다.
이제 세션과 토큰을 동작방식에 대해 알아봅시다.
세션 기반 인증
세션기반 인가는 사용자의 인증 정보가 서버의 세션 저장소에 저장되는 방식입니다.사용자가 로그인을 하면, 해당 인증 정보를 서버의 세션 저장소에 저장하고, 사용자에게는 저장된 세션 정보의 식별자인 Session ID를 발급합니다. 발급된 Session ID는 브라우저에 쿠키 형태로 저장되지만, 실제 인증 정보는 서버에 저장되어 있습니다.
브라우저는 인증 절차를 마친 이후의 요청마다 HTTP Cookie 헤더에 Session ID 를 함께 서버로 전송합니다. 서버는 요청을 전달받고, Session ID에 해당하는 세션 정보가 세션 저장소에 존재한다면 해당 사용자를 인증된 사용자로 판단합니다.
(토큰이랑 비슷해보이죠?)
토큰 기반 인증
세션 기반 인증이 인증 정보를 서버에 저장하는 방식이라면, 토큰 기반 인증은 인증 정보를 클라이언트가 직접 들고 있는 방식입니다. 이때 인증 정보가 토큰의 형태로 브라우저의 로컬 스토리지(혹은 쿠키)에 저장됩니다. 토큰의 종류에 따라 다르겠지만, 대표적인 토큰인 JWT의 경우 디지털 서명이 존재해 토큰의 내용이 위변조 되었는지 서버측에서 확인할 수 있습니다.
토큰 기반 인증에서는 사용자가 가지고 있는 토큰을 HTTP 의 Authorization 헤더에 실어 보냅니다. 이 헤더를 수신한 서버는 토큰이 위변조 되었거나, 만료 시각이 지나지 않은지 확인한 이후 토큰에 담겨있는 사용자 인증 정보를 확인해 사용자를 인가합니다.(실제 적용은 아래 포스팅을 참고해주세요)
[JWT]Spring Security + JWT 로그인 구현하기 (tistory.com)
[JWT]Spring Security + JWT 로그인 구현하기
이제 spring security의 작동원리에 대해 알아보았고 JWT를 이용해서 로그인을 구현하는 방법을 알아보겠습니다. 스프링 시큐리티는 기본적으로 세션을 기반으로 한 인증이 진행되는데, JWT(Json Web Tok
gogowlgml.tistory.com
이제 동작방식을 알아봤으니 본격적으로 차이점을 알아봅시다
세션인증 VS 토큰 인증
1. 사이즈
세션의 경우 Cookie 헤더에 세션 ID만 실어 보내면 되므로 트래픽을 적게 사용합니다. 하지만 JWT는 사용자 인증 정보와 토큰의 발급시각, 만료시각, 토큰의 ID등 담겨있는 정보가 세션 ID에 비해 비대하므로 세션 방식보다 훨씬 더 많은 네트워크 트래픽을 사용합니다.
안정성과 보안
세션
세션의 경우 모든 인증 정보를 서버에서 관리하기 때문에 보안 측면에서 조금 더 유리합니다. 설령 세션 ID가 해커에게 탈취된다고 하더라도, 서버측에서 해당 세션을 무효 처리하면 되기 때문입니다.
또한 세션은 서버측에서 저장/관리하기 때문에 상대적으로 온전한 상태를 유지하기 유리합니다.
하지만 여전히 공격의 위험이 있기에 유효기간, HttpOnly, Secure 옵션 등을 주어 쿠키에 저장합니다.
세션과 같은 경우에는 모든 데이터가 서버에 저장되기 때문에 아무나 함부로 열람할 수 없으므로 저장할 수 있는 데이터에 제한이 없습니다.
토큰
토큰의 경우 그렇지 않다. 토큰은 서버가 트래킹하지 않고, 클라이언트가 모든 인증정보를 가지고 있습니다. 웹 브라우저측 (local storage, 혹은 쿠키 등)에 저장되기 때문에 공격에 노출될 가능성이 더 큽니다. 떠라서 토큰이 한번 해커에게 탈취되면 해당 토큰이 만료되기 전까지는 속수무책으로 피해를 입을 수 밖에 없습니다.
이런 경우를 대비해 토큰에는 민감한 정보를 담지 않습니다. 또한 JWT 특성상 토큰에 실린 Payload가 별도로 암호화 되어있지 않으므로, 누구나 내용을 확인할 수 있습니다. 따라서 Payload에 민감한 데이터는 실을 수 없습니다. 즉, Payload 에 실을 수 있는 데이터가 제한됩니다.
그리고 유효기간을 짧게 설정해 공격에 노출될 수 있는 시간을 최소화합니다.
하지만 짧은 주기로 토큰이 무효화되면 서비스 사용자는 계속 로그인을 해줘야 하는 번거로움이 있기 때문에
애초에 로그인(인증)시 refresh token이라는 것을 추가적으로 발급합니다.
refresh token은 좀 더 긴 유효기간을 가졌으며 최대한 안전한 곳에 저장됩니다.
기존의 토큰이 만료되거나 변질되면 refresh token을 통해 토큰을 재발급합니다.
확장성
위와같은 토큰의 단점에도 불구하고 최근 웹 어플리케이션이 토큰 기반 인증을 사용하는 이유가 바로 이 확장성입니다.
세션은 서버에 저장되기 때문에 한꺼번에 다중 접속자가 발생한다면 과부하가 걸릴 수 있습니다.
그럼 과부하를 덜어주기 위해 서버를 여러 대를 두면 되겠죠?
하지만 또 서버가 여러대라면 세션을 쓰기가 복잡해집니다.
일반적으로 웹 어플리케이션의 서버 확장 방식은 수평 확장을 사용합니다. 즉, 한대가 아닌 여러대의 서버가 요청을 처리하게 되는 건데요. 이때 별도의 작업을 해주지 않는다면, 세션 기반 인증 방식은 세션 불일치 문제를 겪게 됩니다. 이를 해결하기 위해서 Sticky Session, Session Clustering, 세션 스토리지 외부 분리 등의 작업을 해주어야합니다.(추가 비용 발생)
* sticky session은 처음 지정받은 서버만 사용할 수 있기 때문에
해당 서버가 터지거나 과부하가 걸려도 어찌할 도리가 없습니다.
session clustering은 모든 서버마다 세션을 복사해줘야 하기 때문에
상당한 메모리를 요구할 뿐 아니라 매 로그인마다 오버헤드가 크게 발생합니다.
하지만, 토큰 기반 인증 방식의 경우 서버가 직접 인증 방식을 저장하지 않고, 클라이언트가 저장하는 방식을 취하기 때문에 이런 세션 불일치 문제로부터 자유로울 수 있습니다. 이런 특징으로 토큰 기반 인증 방식은 HTTP의 비상태성(Stateless)를 그대로 활용할 수 있고, 따라서 높은 확장성을 가질 수 있습니다.
서버의 부담 (서버 분산 / 클러스터 환경에서 드러나는 결정적인 차이)
요즘 많은 서비스들은 서버 과부하 부담을 줄이기 위해 여러 서버를 두고 서비스를 운영합니다.
그리고 앞서 언급했듯 HTTP는 stateless, connectionless 하기 때문에 request마다 내가 접속한 서버가 달라질 수도 있습니다.
이렇게 되어 버리면 session 정보가 없는 다른 서버에 접속할 때마다 계속 로그인해줘야 합니다.
서버 분산 환경에서는 로드 밸런서가 각 request에 대한 서버를 지정해줍니다.
세션 기반 인증 방식은 서비스가 세션 데이터를 직접 저장하고, 관리한다. 따라서 세션 데이터의 양이 많아지면 많아질수록 서버의 부담이 증가할 것 입니다.
하지만 토근 기반 인증 방식은 서버가 인증 데이터를 가지고 있는 대신, 클라이언트가 인증 데이터를 직접 가지고 있습니다. 따라서 유저의 수가 얼마나 되던 서버의 부담이 증가하지 않습니다. 따라서 서버의 부담 측면에서는 세션 기반 인증 방식보다는 토큰 기반 인증 방식이 조금 더 유리함을 알 수 있습니다.
물론 세션용 서버를 따로 두고 쓰는 방법도 있습니다.
하지만 만일을 대비하여 서버를 복제해두어야 합니다.
애초에 토큰방식을 사용한다면 추가 서버 없이 인증/인가를 처리할 수 있습니다.
참고 블로그
https://fierycoding.tistory.com/69
https://hudi.blog/session-based-auth-vs-token-based-auth/
'개발자 > workflow 리팩토링 프로젝트(SpringBoot,JPA,MySQL)' 카테고리의 다른 글
[JWT+Redis]Redis를 이용해 최신 JWT만 이용하게 하기 + accessToken 만료시 재발급 + JWT 로그아웃 - 2 (0) | 2023.08.01 |
---|---|
[JWT+Redis]Redis를 이용해 최신 JWT만 이용하게 하기 + accessToken 만료시 재발급 + JWT 로그아웃 - 1 (1) | 2023.07.29 |
[JWT]Spring Security + JWT 로그인 구현하기 (0) | 2023.07.02 |
[Spring Security] 스프링 시큐리티 동작 원리 - 1 (0) | 2023.07.01 |
[Spring boot] Spring 처리단계(Filter,DispatcherServlet,InterCepter,controller) (0) | 2023.06.27 |