개발 일기

[인증] JWT 와 세션 방식 비교 본문

Tech/배워서 남주기

[인증] JWT 와 세션 방식 비교

flow123 2022. 7. 16. 17:26

인증/인가 기능 구현

 

로그인/회원가입/메인 화면을 제외하고는 인증과 인가 과정을 거쳐야 합니다.

여기서 인가는 사용자의 권한을 확인하는 작업이며, 인증은 사용자의 신원을 확인하는 작업입니다 (서버가 갖고 있는 회원 정보와 일치하는지, 즉 가입 회원이 맞는지). 

 

유저가 상품을 주문하는 상황을 가정해봅시다. 서비스는 유저의 주문이라는 행위를 기록하기 위해, 인증을 필요로 할 것입니다. 제가 만들고 있는 서비스는 판매자만 상품을 등록할 수 있습니다. 더불어, 등록한 상품은 해당 상품을 등록한 판매자만 수정할 수 있습니다. 이 과정에서 판매자의 권한을 확인해야 합니다.

 

그러면 판매자는 제품을 등록하고, 수정하고, 재고를 변경할 때마다, 로그인을 해야할까요? API 를 이동할 때마다 로그인을 한다면 너무 번거롭겠죠. 실제로 우리가 이용하는 서비스는 한 번 로그인을 하면, 웹 페이지에 머무는 일정 시간동안 로그인 상태가 유지되는 경우가 많습니다. 매번 로그인을 거치는 것은 곧 암호화된 해시값을 꺼내서 입력한 비밀번호와 확인하는 작업을 수반합니다. 즉, 리소스가 많이 들기 때문에 이를 간단히 할 필요가 있는 것입니다.

 

본 포스트 에서는 대표적인 인증 방식인 세션과 JWT 방식을 비교해보겠습니다. 

세션과 JWT 비교

설명을 시작하기 전에, 세션과 JWT 토큰의 전반적인 차이점을 아래 표로 비교해보겠습니다.

 

  세션 JWT 토큰
상태성 Stateful Stateless
저장 위치 - 브라우저 내에 세션 ID 저장
- 서버 측 DB에 인증 정보 저장.
서버 메모리에 세션이 저장되기에, 서버가 fail 될 경우 세션 객체를 분실 위험이 존재.
유저의 브라우저 내에 저장
확장성
(scalability)
서버가 여러 대인 상황에서는 별도 처리를 해줘야 함
(Redis, DB에 따로 저장 등)
별도 처리 필요 X.
세션과 달리 인증을 위해 서버를 거칠 필요가 없음.
따라서 서버 확장에 유리 .
보안 매번 DB에서 가져오기 때문에, 토큰보다 안전함 취약성 노출을 막기 위해,
보안문제를 대비하고 해결해야 함.
속도 DB를 거쳐서 인증하기 때문에, 레이턴시 증가. 브라우저에서 정보를 가져오기에 성능이 더 빠름 
비고  보안이 민감한 비즈니스 (EX. 금융) 구현이 편리하고 경제적
속도가 사용자 경험에 중요한 비즈니스에 적절할 수 있음. (EX. 게임)

JWT 는 어떻게 동작하는가?

(1)  토큰의 구성

 

JWT 토큰은 JSON 객체 형태의 데이터 입니다.

토큰은 암호화된 아래의 3가지 데이터로 구성되어 있습니다.

  • Header
  • Payload
  • Signature

사이트(https://jwt.io/)에 들어가시면, 위의 이미지처럼 Encoded 된 토큰과 이를 Decode 된 결과를 확인하실 수 있습니다. jwt 는 만들어진 토큰을 서버의 비밀키로 복호화해서 데이터를 꺼냅니다.

JWT 토큰은 사용자 데이터를 따로 저장하지 않기 때문에, stateless 방식입니다.

 

stateless (무상태) 라고 하는 이유는, 서버가 유저 인증을 위해 저장해야 하는 정보가 없기 때문입니다.

토큰 자체로 토큰의 소유주를 인증할 수 있는 모든 정보를 담고 있습니다.

AccessToken이 탈취될 경우 보안 취약성이 있습니다. refresh Token 방식이 이러한 단점을 보완한 방식 입니다.

 

(2)JWT 의 AccessToken + Refresh Token 방식

 

Refresh Token은 Access Token을 재 발급 받기 위해 쓰는 토큰입니다.

Access Token의 유효기간이 짧기 때문에, 만료 될 때마다 새로 발급해주는 것입니다.

Refresh Token 의 유효 기간이 더 길기 때문에, RefreshToken이 가능한 기간동안 Access Token을 새롭게 발급 받을 수 있습니다 (따라서 유저는 다시 로그인 할 필요가 없습니다)

과정

1. 로그인 시 아래 두 개의 토큰을 발급 받습니다.

 

(1) 수명이 짧은 Access Token

(2) 수명이 보다 긴 Refresh Token

 

2. 두 토큰을 발급한 후,refresh 토큰 값을 DB에도 저장 합니다.

3. 유저는 Access Token의 수명이 다하면, RefreshToken 으로 Access Token 발급 요청을 보냅니다.

4. 서버는 유저가 보낸 Refresh Token 을 DB에 저장된 값과 대조해봅니다. 맞다면 새 Access Token 을 발급해줍니다.

 

서비스에서 유저를 강제로 로그아웃을 시키고 싶다면, 리프레시 토큰을 DB에서 지웁니다.

더 이상의 Access Token을 발급할 수 없게 차단하는 것입니다. 그럼에도 짧게나마 액세스 토큰이 살아있는 동안은, 바로 차단할 방법이 없습니다.

 

결론적으로, jwt 는 구현하기 편리합니다. 하지만 비즈니스에서 구현할 때는 현재 서비스에 JWT 만으로 보안이 충분히 지켜질 수 있는지 점검해보아야 합니다.


세션은 어떻게 동작하는가?

 

세션의 특징

 

토큰과 달리 세션은 stateful 합니다. 즉, DB가 사용자의 상태, 인증 정보를 기억하고 있습니다.

따라서 서버 확장 시 고려해야 할 것이 많습니다. 다중 서버 환경에서는 인증 객체 저장소를 중앙화하는 작업이 필요합니다 (Redis를 사용하거나, DB에 저장하는 방법이 많이 쓰입니다). 성능이나 스케일 업 환경에서는 JWT 가 더 유리하지만, 세션은 통제하기 더 쉽다는 장점이 있습니다. (ex. PC에서 로그인 후 모바일로 로그인 하면, pc의 세션 정보를 만료 시킬 수 있습니다. 서버 측 DB에 세션 정보가 보관되어 있기 때문입니다. JWT는 서버에서 데이터를 보관하지 않는 STATELESS 이기 때문에, 위에 설명 드렸듯 이미 토큰을 발급한 후에는 처리에 한계가 있습니다.

 

세션 ID는 유저가 로그인 작업을 한 유저의 브라우저에 쿠키 형태로 저장됩니다. 

유저는 이 세션 ID 에 접근할 수 있고, 브라우저에 인증 객체가 노출되지 않고 로그인을 수행할 수 있습니다. 

 

결론 

두 기술을 검토해 본 뒤, 세션을 사용하기로 결정했습니다.  

JWT  공부하면서 구현은 보다 단순하지만, 보안 면에서 깊게 이해해야할 필요성을 느꼈습니다. 

세션의 경우 다중 서버에서 로그인 객체를 중앙화하는 처리가 필요하지만, 마침 Redis를 공부하면서, Redis를 통해 해결할 수 있음을 알게 되었습니다. 따라서 본 프로젝트에서는 세션과 Redis를 사용할 것입니다.

 

다음 포스팅에서는 세션/쿠키를 사용하여 인증 기능을 직접 구현해보고, 

이후 Redis를 통해 로그인 객체 정보를 중앙화하는 작업을 소개하겠습니다. 

 

참고 자료 

https://devops.com/session-tokens-vs-jwts-choosing-your-session-management-solution/

스프링 MVC 2편 김영한님 강의

얄팍한 코딩 사전: https://www.youtube.com/watch?v=1QiOXWEbqYQ

JWT 대충 쓰면 님들 코딩인생 끝남 - YouTube

https://tansfil.tistory.com/59

Comments