즐코

JWT (ft.세션) 본문

NodeJS

JWT (ft.세션)

YJLEE_KR 2022. 3. 3. 06:36

 

어떤 웹사이트던간에 회원/비회원에 따라 페이지가 구분된다. (마이페이지, 회원정보 수정, 게시판 페이지 등..)

즉, 서버는 사용자를 구분하여 사이트 내 각각의 기능들을 허용해줄지 말지 결정해서 응답을 해야한다.

 

그래서 웹사이트 내에서 사용자가 페이지 이동 시,

서버가 각 페이지에서 이 사용자를 기억하기 위해 즉, 사용자의 로그인 상태 유지를 위해 필요한게 인증과 인가이다.

 

 

1. 인증(Authentication) & 인가(Authorization) 과 세션 리마인드..

 

 

인증(Authentication)  인가(Authorization)
사용자의 id와 pw를 확인해 회원임을 인증하는 과정
(로그인/회원가입)
로그인을 하고나서 (회원임을 인증하고 난 이후에)
한 웹사이트 내에서 여러 페이지/서비스를 이용할 때
서버가 이 사용자가 권한이 있는지 없는지 확인하는 절차 

 

 

근데 이 서버는 사용자의 페이지 GET/POST 요청마다 로그인 된 상태인지 아닌지 어떻게 아는걸까?

그리고 1명의 사용자가 아니라 다수의 사용자가 접속할 경우 이 한명한명을 어떻게 구분하는걸까?

 

그래서, 예전엔 사용자의 로그인 상태 유지를 위해 세션+쿠키란 개념을 배웠다.

 

https://yjleekr.tistory.com/42

 

세션 (ft.쿠키) / 세션 기반 로그인 구현

1/ 세션 1. 세션이란? 2. 쿠키없이 세션으로만 가능? 3. 세션은 어떻게 사용하나 ? 2/ 세션 기반 로그인 기능 구현해보기 1/ 세션 1. 세션이란? 어제 배웠던 쿠키는 사용자 데이터(쿠키내용)의 저장을

yjleekr.tistory.com

 

세션을 다시 기억해보자면,

 

1/ 사용자가 로그인 시 서버가 session ID란 값과 사용자의 정보를 매칭하여 서버 측 메모리 or 하드디스크 or 세션DB 등에 저장한다.  {session id : 사용자 정보}

2/ 여기서 session ID만 사용자의 브라우저에게 던져주고, 브라우저는 쿠키상에 그 session ID를 저장해둔다.

3/ 사용자는 매 요청마다 이 session ID를 가지고 있는 쿠키를 서버에게 보낸다.

4/ 서버는 세션 DB에 저장해둔 {session id : 사용자 정보} 와 사용자의 쿠키에 있는 session ID를 비교하는 작업을 거쳐서 인가를 진행, 로그인 상태를 유지시킴

 

 

근데 세션엔 단점이 있다. 

 

사용자 정보를 session id와 함께 세션 DB상에 저장해야하니까 사용자가 늘어남에 따라 세션 DB를 늘려야하므로 물리적으로 한계가 있다.  

 

이런 문제점 없이 가를 구현하기 위한 또 다른 방식 중 하나가 토큰 방식이고, 우린 그 중 JWT를 배울 것이다.

 


 

2. JWT (Jason Web Token) 

 

 

세션에서 서버가 사용자에게 session ID를 준 것처럼,

JWT 같은 토큰 방식에서도 사용자가 로그인 시에 session id처럼 token을 사용자에게 던져준다.

 

대신, 세션과 다른 점은 사용자 정보와 이 token이란 걸 매칭해서 서버쪽에 저장해두지 않는다.

서버 쪽 저장 없이 그냥 token을 사용자에게만 준다. 즉, 서버는 기억하거나 저장하는 게 없다, 세션 DB가 필요 없음

 

그럼 이 token은 어떻게 만드는걸까

인코딩된 2가지 데이터(header, payload)와 암호화된 1가지 데이터(signature) 총 3가지 데이터를 붙여서 만든다.
마침표(.)로 구분하여 붙여준다

Token = Header.Payload.Signature

 

 

우선 가운데 있는 payload부터 알아보자. 

 

 

1. payload

 

이 payload에는 공개해도 보안에 문제없는 정보들을 JSON 타입으로 담는다.

이렇게 토큰에 담긴 사용자 정보 등의 데이터를 클레임이라고 한다.

- 누가 누구한테 발급했는지, 이 토큰의 유효기간, 사용자의 정보 중 id, 이름, 레벨 등.. 

 

=> 근데 이때, 사용자가 고의로 정보를 바꿀 경우에 대비해서 header와 signature가 존재한다.

 

 

2. header

 

2가지 정보가 담겨 있다.

  #1 토큰의 타입 type : JWT (우린 토큰 방식들 중 JWT를 배울거니까 고정값으로 JWT를 넣는다)

  #2. 알고리즘 alg : 3번째 signature 값을 만드는데 사용하는 알고리즘

                            여러 암호화 방식 중에서 선택해서 넣는다. (HS256 등)

 

 

3. Signature

헤더 + 페이로드 + '서버쪽에 숨겨둔 시크릿 키'
=> header에서 설정한 암호화 알고리즘에 넣고 돌리면? 

=> 3번 서명값이 나옴

 

사용자가 요청 때마다 토큰을 주면,

토큰 내부의 헤더 + 페이로드 와 서버가 갖고 있는 비밀키를 같이 돌려서

그 계산된 결과값이 3번 signature와 일치하는 결과(true)가 떨어지는 지 확인해야함

 

그래서 2번 payload에 있는 사용자의 정보가 조금이라도 변경된다면 이 token값이 원래 서버가 사용자에게 준 token과 아예 다른 키로 바껴져 있을 것이다.

 


 

그렇다고 사용자의 상태 유지를 위한 인가방식으로 JWT만 쓰나?

 

그것도 아니라고 함

 

왜냐하면, 세션처럼 사용자의 모든 정보를 세션값과 함께 매칭해서 세션 DB상에 갖고 있지 않고 토큰만 던져주는 방식이라 서버에 부담은 없지만 JWT만 쓰면 사용자 추적이 어려워 통제하기가 어려워진다.

 

ex) 사용자를 강제 로그아웃시키거나 넷플릭스처럼 여러 계정을 쓸 때 이 계정 갯수를 제한한다던가,

해커가 토큰 탈취시 무효화시킨다거나.. 

 

세션 방식은 세션 DB상에서 세션ID를 삭제하면 되는데,

JWT방식에선 사용자만 토큰을 가지고 있으니까 이걸 서버가 강제로 삭제할수 없다.

세션처럼 사용자의 모든 정보를 통제하는 게 아니라, 이 토큰이 유효한가 아닌가의 여부만 따지기 때문이다.

 

그래서, 이 token의 유효기간을 짧게 잡는다. 근데 이럴 경우 로그인이 너무 빨리 풀려 버릴 수 있다.

 


 

JWT의 이런 방식을 보완하는 방법이 있다.

 

1/  로그인하면 사용자에게 토큰을 2개 발급해줌

유효기간이 엄청 짧은 access token + 반대로 유효기간이 긴 refresh token

 

2/ refresh 토큰은 상응값을 서버 DB에도 저장함

 

3/ 사용자는 access token 수명이 다하면 refresh token을 보낸다.

 

4/ 서버는 그걸 DB에 저장한 값과 대조해보고 새로운 access토큰을 발급해준다.

이 refresh 토큰만 안전하게 관리된다면, access 토큰이 만료될때마다 다시 로그인할 필요가 없이 새로운 access 토큰을 받게 된다.

 

5/ 로그아웃 시엔 이 refresh 토큰만 DB에서 지워버리면 된다.

 

 

Comments