카테고리 없음

JWT / Session

문앵 2022. 12. 29. 11:11

JWT(Json Web Token)

 

인증 (authentication)-> 로그인 할 자격이 있는지 없는지 체크

인가 (authorization)-> 로그인을 한 상태인지 아닌지 체크

 

로그인 방식

 

1. 세션 

 

*세션 로그인 과정 : 유저가 로그인에 성공 -> 서버에서는 세션 표딱지 출력 -> 세션 표딱지하나를 찢어서 반은 유저의 브라우저로 보냄, 반은 서버의 책상 (메모리)에 얹어두거나  서랍 (하드디스크) , 창고 (데이터베이스)에 넣어두기도 함-> 유저의 브라우저는 받은 표딱지를 session ID 라는 이름의 쿠키*로 저장해둠 (*쿠키 : 브라우저상에 저장되는 정보)

 

* 장점 : 메모리에 저장해두는 방식으로 사용시 빠르다. session DB에 저장된 sessionID를 쿠키에 담아 브라우저 -> 서버 -> DB 가 서로 주고받는 방식은 서버단에서 세션을 즉각적으로 제어할 수 있다. (보안 공격시 즉각 대응 가능, 원하지 않는 기기에서 원격 로그아웃 가능, 넷플릭스처럼 계정 공유 숫자 제한 가능 등등... )

 

* 문제점 : 세션 표딱지를 메모리상에 저장해두게 되면 , 속도는 가장 빠르지만 서버에 문제가 생겼다거나 할때 서버를 재부팅하면 메모리에 있는 정보는 모두 날아감. 세션 표딱지를 하드디스크에 보관하는 방식은 서버를 여러대 사용하고있을 경우 문제가 생김. 만약 로그인은 1번서 버에서 하고 이메일 요청은 2번 서버에서 하게 되면 2번 서버에는 1번서버의 세션 표딱지를 가지고있지 않으므로 이땐 다시 로그인을  해야하는 문제가 생김.

마지막으로 데이터베이스에 세션정보를 저장하는 방식은 속도가 현저히 느려진다는 단점이 있음. 그래서 레디스(redis)나 Memcached 같은 메모리형 데이터베이스 서버 (비유하자면 길다란 공용 책상을 따로 둬서 거기에 저장)를 사용하기도 함. 

 

 

 

2. jwt 사용

 

* jwt 특징

긴 문자열로 이뤄져있고 문자열 중간에 포함 돼있는"."을 기준으로 세부분으로 구분됨.

{ xxxxxxxx.yyyyyyyyy.zzzzzzzzz }

xxxx.. -> header

yyyy.. -> payload

zzzz.. -> verify signature

 

- payload : 페이로드를 base64로 디코딩해보면 json 형식으로 여러 정보가 들어있다 

이 토큰을 누가 누구에게 발급했는지 , 이 토큰이 언제까지 유효한지 , 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용 (ex. 관리자 레벨 , 사용자 닉네임 등등)

이렇듯 토큰에 담긴 사용자 정보 데이터를 claim 이라고 한다. 

 

- header : 헤더를 디코딩해보면 두가지 정보가 담겨있다 . 첫번째로는 타입 (여기는 항상JWT다) 이고 두번째는 alg (알고리즘의 약자)가 들어간다. alg에는 3번 verify signature 를 만드는데 사용되는 알고리즘이 지정된다. sha256등 암호화 방식을 선택할 수 있다.

header + payload + '서버에 저장 돼있는 시크릿키' 를 alg 의 암호화 방식으로 암호화 하면 3번의 verify signature가 되는 것이다 !

 

* jwt 인증 및 인가 과정 : 유저가 로그인 -> jwt토큰 생성 -> 유저에게 토큰 줌 -> 유저가 이후 요청을 보낼때 이 토큰을 함께 보냄 -> 서버에서는 이 토큰을 받으면 1번 header와 2번 payload 값을 서버의 시크릿키로 암호화 알고리즘으로 돌려서 3번 signature와 일치하는지를 확인해본다.  

 

* 장점 : 데이터베이스를 거치지 않고 서버단에서 인증할 수 있어 서버의 부하를 덜어준다.  브라우저 상에서만 사용할 수 있는 session과 달리 token은 android나 ios 같은 네이티브 앱에서도 사용할 수 있다.

 

* 단점 & 한계 :

보안상 취약점 존재.  jwt : stateless(시간에 따라 상태값에 영향을 안받는다) / session : statefull

? stateless란 서버로 가는 모든 요청이 이전 리퀘스트와 별개로 독립적으로 이루어지는 것. 요청끼리의 연결이 없음 (즉 메모리가 없음). 따라서 요청이 끝나면 서버는 내가 누군지 기억하지 못함 매 요청마다 내가 누군지를 말해줘야 함 ? 

 

jwt는 한번 악의적인 탈취를 당했다고 하면 유효기간이 다 할 때 까지 서버단에서 이를 제어할 수 있는 방법이 없음.

이에 대한 보완책으로 리프레시 토큰과 엑세스 토큰을 함께 사용하는 방법이 있음. ( 리프레시토큰과 엑세스토큰을 사용하는 방법은

여러가지임. 그중 예를 들자면 )

-> 유저가 로그인을 했을 때 리프레시 토큰(유효기간이 길다. 2주정도) & 엑세스 토큰 (유효기간이 짧다)을 함께 발급한다.

이때 리프레시 토큰은 디비에도 저장된다. 유저가 로그인 인가시 엑세스 토큰의 수명이 다하면 리프레쉬토큰을 보낸다.

리프레쉬토큰을 받은 서버는 데이터베이스의 값과 이 토큰을 비교해서 상응하는 값이 있으면 다시 엑세스토큰을 새로 발급해서 함께 준다.

 

만약 엑세스 토큰이 탈취 당하더라도 리프레쉬 토큰을 디비에서 제어해버리면 , 해당 계정은 엑세스 토큰의 수명(짧음)이 다하면

더이상 로그인 인가를 받지 못하게 되고 다시 로그인을 해야한다. 

 

그러나 이마저도 엑세스 토큰의 수명이 남아있는 동안은 서버에서 해당 계정을 제어할 방법이 없기 때문에 로그인 인가를 해줄 수 밖에 없다는 한계가 존재한다.

 

 

참고 : 

https://youtu.be/1QiOXWEbqYQ

 

https://youtu.be/tosLBcAX1vk

 

반응형