상세 컨텐츠

본문 제목

jwt

TIL (Today I Learned)

by NayC 2022. 1. 27. 07:24

본문

728x90

 

 

 

문제 상황

1. 

로그인할 때, 사용자가 입력하는 id, password를 db에 기억하고 있다가 같으면 로그인  X

-> db가 해킹 당하면 전부 유출되는 문제가 존재.  

 

2.

페이지를 들어갈 때마다 로그인 상태를 '유지' 시켜주는 문제

 

So, 인증, 인가가 중요

- 인증 : Authentication (로그인)

- 인가 : Authorization (로그인이 유지되는 상태에서 일어나는 것) 

 

Authorization 전통적인 방식 - session

1. 사용자가 로그인에 성공하면 '서버'는 '세션 딱지'같은 걸 출력한다. 
  이 딱지를 찢어서 반쪽은 '사용자의 브라우저'로, 반쪽은 '메모리, db ... ' 등 에 저장함. 

  (메모리에 저장하는게 다른 저장 공간보다는 빠르게 처리해준다.)

2. 브라우저가 이 딱지를 session ID란 이름의 쿠키로 저장 (쿠키 : 브라우저에 저장되는 정보)

    이 브라우저는 다음 사이트에 요청을 보낼때마다 이 딱지를 실어 보냄. 

3. 요청에 session ID라는게 들어오면 -> 서버는 메모리에서 맞는 짝이 있는지를 찾는 것 

 

어떤 사용자가 서버에 로그인 되어있음이 지속되는 상태를 '세션'이라고 함

- 서버가 표 반쪽을 기억해두고 있는 자체

 

허점

- 사용자가 동시에 많이 접속하면 메모리가 부족해질 것
   -> 메모리 특성상 서버에 문제가 있어서 꺼져버리기라도 하면 정보가 날라감 (휘발성)
        사용자는 다시 로그인해야하는 상황이 발생

- 메모리 대신 하드에 저장을 하면? 메모리보다 느리다.

- 서버를 여러대 둔다면? (서버를 분산해서 load balancing)

   만약에 로그인은 1번 서버, 검색 요청하는 서버는 2번 서버에 연결을 하면 2번 서버에는 그 사용자에 대한 정보(딱지)가 없으니 세션 유지가 되지 않음. 

- 복잡한 구성과 환경에서 (사용자가 많아져서 메모리가 부족해진다던지, db에 연결을 하면 무거워진다던지) 어떤 상태를 기억해야한다는 설계가 힘듦 

 

session 방식 해결 -> '토큰 방식'인 jwt 

- json web token

- jwt를 사용하는 서비스에서는 사용자가 로그인을 하면 'token'이라는 표를 (세션때와 마찬가지로) 출력해서 줌

  대신 세션 때와 다른 점은 '찍어서 주지 않고' 그냥 준다. 즉, 서버가 뭔가를 기억하고 있지 않다는 점

- 토큰의 생김새 : feihfisfnjskldoujkalHUgirgeg....

   인코딩/암호화된 3가지 데이터리를 이어붙임 (잘 살펴보면 중간에 마침표가 2개 들어가있다.)
   각각 header, payload, verify signature로 구분됨 

(1) payload 부분 

- (base64로) 디코딩을 해보면 json 형식으로 여러 정보들이 들어있음 

   이 토큰을 누가 누구에게 발급했는지, 언제까지 유효한지, 서비스가 사용자에게 이 토큰을 공개하기 원하는 내용 (사용자 닉네임, 관리자 여부 등) 등의 정보가 있는데 서비스 측에서 원하는대로 담을 수 있음

- 이렇게 토큰에 담긴 사용자 정보 등의 데이터를 claim이라고 함

- 사용자가 이런 정보(claim)을 갖고 있으니, 서버는 요청이 들어올 때마다 일일히 db에서 찾아봐야 할 수고가 줄어들게 됨 

- 허점 : 디코딩해서 볼 수 있기에, 보안에 허점이 존재 (그래서 header, verify signature가 필요) 

(2) header 부분

- 디코딩해서 보면

1) type : 토큰 타입 (여기에는 언제나 jwt가 들어간다. 타입이 jwt여야 jwt인 것이기에 고정값이다.)

2) alg : 알고리즘의 약자.  verify signature을 만드는데 사용될 알고리즘이 지정됨. 

    예를 들어 HS256 등 여러 암호화 방식 중 하나를 지정한다. 

    header, payload, '서버에 감춰놓은 비밀 값' 이렇게 3개를 이 알고리즘에 넣으면 -> verify signature가 나온다.

 

- 서버는 요청에 토큰이 들어오면, header, payload, '서버에 감춰놓은 비밀 값'을 계산해봐서 계산된 결과값이 verify signature 와 같은지를 확인한다. 

- 만약 header, payload 중에 조금이라도 어떤 정보가 수정되었다면 패스가 되지 않음. 

 

✅ 이처럼 시간에 따라 바뀌는 어떤 상태값을 '안' 갖는 걸 'stateless하다'고 함 (반대는 stateful

 

그럼 다 jwt 방식으로 쓰면 되는 것인가 

- 세션을 대체하기에는 jwt 방식에는 큰 결점이 존재

   세션처럼 stateful해서 모든 사용자들의 상태를 기억하고 있으면, (구현이 부담스럽지만) 기억하는 대상의 상태를 언제든 제어할 수 있음

   ex) 기기 한 대에서만 로그인 가능한 서비스를 만들었는데, 세션 방식으로 하면 다른 기기에서 로그인을 해왔을 때 pc에서는 로그아웃되도록 컨트롤 가능

<-> 반대로 토큰은 한 번 줘버리 토큰은 회수도 추적도 불가능. 즉, 내가 정보를 가지고 있지 않아서 편하기는하나 통제가 불가능

       더 최악의 상황은 어떤 해커가 토큰을 가져가버리게 되면 그 토큰을 무효화시킬 방법이 없음

- 서버가 아는 것은 오직 토큰이 유효한지 여부. 유저 계정을 잘 관리해야 하는 경우 session을 활용한다. 

   (session처럼 db에 저장하지 않기 때문에 현재 인스타그램에 로그인한 계정이 몇 개인지, 넷플릭스 한 아이디에 몇 명의 유저가 쓰고 있는건지 등을 확인 불가)

- 그래서 생각보다 jwt를 많이 쓰지 않는다.

   jwt를 사용하는 경우는 만료 시간을 가깝게 잡아서 토큰의 수명을 아주 짧게 주는 경우. 

   1) access 토큰 :  수명이 몇 시간이나 몇 분이하로 짧음 

   2) refresh 토큰 : 꽤 길게 (2주 정도) 수명이 있음

- access 토큰과 refresh 토큰을 발급하고 클라이언트에게 보냄

- refresh 토큰은 상용값을 db에도 저장함

- 클라이언트는 access 토큰 수명이 다하면 refresh 토큰을 보냄

- 서버는 그 토큰을 db에 저장된 값과 대조해보고 맞다면 새로운 access 토큰을 발급해줌

- refresh 토큰만 안전하게 관리된다면 이게 유효할동안은 access 토큰이 만료될 때마다 다시 로그인할 필요가 x

 


(아래는 기존에 작성했던 내용인데 삭제하려다가, 위에 내용으로 확실히 개념 잡고 다시 읽어봐도 될 것 같아서 남긴다. (흐름이 산재되어 있기에 개념 잡고 읽으면 흐름을 스스로 잡는데 도움이 될 듯ㅎㅎ)) 

 


 

 

쿠키

  • 서버가 나의 브라우저에 데이터를 넣을 수 있음
    for ‘나'를 기억하기 위해
  • 만약 내가 구글에 접속하고 검색어를 입력하면 서버는 내 요청에 대해 response를 주는데 이때 같이 ‘쿠키’도 주는 것. 그리고 내 브라우저는 그 쿠키를 간직해놨다가, 내가 웹사이트에 방문할 때마다 request와 함께 쿠키를 보내게 됨. (들고다니는 열쇠같은 것
  • 쿠키는 인증에 대한 정보 뿐만 아니라 다른 정보들도 담을 수 있음. ex) 언어 설정 (그래서 내가 다음에 방문할 때는 영어가 아니라 한국어가 뜬다던지)
  • 제한 (1) 쿠키는 도메인에 따라 제한됨. 만약 내가 구글 쿠키를 받았으면 구글 웹사이트에서만 유효
  • 제한 (2) 유효기간 존재. 서버가 정함

 

stateless 개념

  • 서버로 가는 요청들이 이전 request와는 독립적으로 다뤄진다는 것
  • 요청이 끝나면 서버는 이 요청이 누구건지 다 잊어버림 -> 요청할 때마다 우리가 누구인지 알려줘야 함
    ✅ 이 방법 중 하나가 바로, session 

 

session

  • 세션을 활용해서 안드로이드, ios도 다 만들 수 있지만 이때는 쿠키 사용이 불가. (쿠키는 브라우저에만 있기에)
    ✅ 그래서 token을 사용
  • 세션에서 기억해둘 점은, 현재 로그인한 유저들의 모든 세션 id를 db에 저장해야한다는 점
    요청이 올때마다 서버는 쿠키를 받고, 세션 id를 보고, 세션 id와 일치하는 유저를 찾음. 즉 요청이 올때마다 db를 찾아야 함
    ✅ jwt가 등장함 (token 형식)

 

jwt

  • 세션 db를 가질 필요 x
    서버는 유저 인증한다고 많은 일을 하지 않아도 됨
  • 로그인하려면 서버에 signed info / token을 서버에 보내야 함
    서버는 토큰을 받으면 해당 사인이 유효한지 체크한 후, 유저로 인증
  • jwt에서 서버는 유저를 인증하는데 필요한 정보를 '토큰'에 저장. 
    해당 토큰을 브라우저 주고.
    (다음에) 페이지 요청시 서버는 해당 토큰이 유효한지만 검증하면 됨 (db를 거칠 필요가 없음)
    <-> session은 세션에 대한 모든 정보가 세션 db에 있어서 세션 id를 줬어야 했다는 점
  • jwt는 암호화되지 않음 (암호화되었다면 아무도 읽을 수 없고, 이해할 수 없음)
    jwt는 누구나 열어서 해당 컨텐츠를 볼 수 있음 (그래서 중요한 내용은 jwt에 두면 안 됨)
  • (단점) jwt를 사용하면 생성된 토큰을 추적하지 않음. (session처럼 db에 저장하지 않기 때문에 현재 인스타그램에 로그인한 계정이 몇 개인지, 넷플릭스 한 아이디에 몇 명의 유저가 쓰고 있는건지 등을 확인 불가)
    - 서버가 아는 것은 오직 토큰이 유효한지 여부
    -> 유저 계정을 잘 관리해야 하는 경우 session을 활용

 

 

캐시

  • 사용 빈도가 높은 데이터를 고속으로 엑세스 할 수 있는 위치에 두는 것
  • ‘바로 사용할 테니까 일단 여기에 두자’
  • 단점) 고속으로 엑세스 할 수는 있지만 데이터를 잃을 위험이 있어서 캐시 데이터가 손실돼도 괜찮은 경우에 주로 사용

 

캐시 vs 쿠키

-> 캐시 로딩 시간을 줄이기 위해 브라우저 (클라이언트 측)에 웹 페이지 자원을 저장하는 데 사용되는 반면, 쿠키 사용자 기본 설정을 추적하기 위해 브라우징 세션을 저장하는 데 사용

 

 

 

 

 

 

출처 : https://youtu.be/tosLBcAX1vk, https://youtu.be/1QiOXWEbqYQ

캐시 vs 쿠키 : https://ko.gadget-info.com/difference-between-cache

캐시 출처 : 책 [it인프라구조]

 

728x90
반응형

관련글 더보기