세션,토큰,JWT가 무엇인가?

윤재열·2022년 5월 26일
0

CS지식

목록 보기
9/16

세션,토큰,JWT 를 공부하기전에 알아두어야할 것이 있습니다.
바로 인증,인가 이 두가지 입니다.

인증 : Authentication

  • 쉽게 말해서 로그인이라고 생각하면 됩니다.
  • 내가 이 사이트에 가입된 회원임을, 즉 특정 서비스에 일정 권한이 주어진 사용자임을 ID,PW 등을 통해 인증을 받는겁니다.

인가 : Authorization

  • 위에서 인증을 받은 사용자가 이후 서비스의 여러 기능들을 사용할때 사용합니다.
  • 예를 들어 네이버에 로그인으로 인증을 하여 내 메일을 열어보고, 나의 블로그도 보고, 댓글도 달 수있는
  • 즉, 내 계정으로만 할 수 있는 활동을 시도할 때 네이버에 내가 로그인 되어 있음을 알아내고 허가를 해주는 것입니다.
  • 로그인이 유지되는 상태에서 일어나는 일이라고 생각하면 쉽습니다.

이제 기본 용어는 공부했으니 본론으로 들어가보겠습니다.

세션 : Session

  • 사용자가 로그인에 성공하면, 서버는 세션 표딱지 라는 것을 출력합니다.(영화관 티켓을 생각합니다.)
  • 이것을 반으로 찢어서 반쪽은 사용자의 브라우저(크롬or엣지)로 보내고,다른 반쪽은 메모리,경우에 따라서는 하드디스크나 DB에 올려 놓는것입니다.
  • 브라우저가 이 표를 Session ID란 이름의 쿠키로 저장하고 , 이 브라우저는 앞으로 사이트에 요청을 보낼때마다 이 표딱지를 실어서 보냅니다.
  • 그래서 요청에 이 표딱지 반쪽, "Session ID"가 실려오면, 서버는 그것을 메모리에서 맞는 짝이 있는지 찾아서 있으면 인가(Authorization)을 해주는 것입니다.
  • 이처럼 Session ID를 사용해서 어떤 사용자가 서버에 로그인 되어있음이 지속되는 이 상태를 "세션"이라고 합니다.

세션의 문제점

  • 메모리는 사용자가 동시에 많은 접속을 해버리면 메모리가 부족해지거나, 서버에 문제가 있어서 꺼져버리면 아무래도 휘발성이다 보니까 모두 없어질 수 있습니다.
  • 서버가 재부팅이 되는 상황이 오면 메모리에 있던것들은 모두 날라가게 됩니다.
  • 그리고 서비스가 어느정도 규모가 있어서 서버를 여러대 두고 사이트를 운영한다고 한다면,
    요청이 들어오면 여러 서버들 사이에 분산을 해서 로드발란싱을 해줍니다.
  • 만약에 로그인은 1번서버, 메일은 2번서버에서 해주는데 2번서버에는 그 사용자의 표딱지 반쪽이 없으니까 세션 유지가 되지 않습니다.
  • 그렇다고 사용자의 요청이 각자 할당된 서버로만 보내지게 하는 것도 번거롭고 까다롭습니다.
  • 다른 방법으로는 DB서버에 넣어두거나 Redis나 MemCached 같은 메모리형 데이터베이스 서버에 놓기도 합니다.
  • 물론 이때도 서버가 복잡한 구성과 환경에서 어떤 상태를 기억해야 된다는 것이 설계하기가 머리아픕니다.
  • 그래서 이런 부담 없이 인가를 구현하기 위하여 고안된 것이 '토큰방식'인 JWT 입니다.

JWT : JSON Web Token

  • JWT를 사용하는 서비스에는 사용자가 로그인을 하면 역시 토큰이라는 를 출력해서 건네줍니다.
  • 대신 세션과 다르게 표를 찢어서 주지 않고 건네 줍니다.
  • 서버가 뭔가를 기억하고 있지 않는 다는 것입니다.
  • 무엇인가를 인코딩 했을 때 처럼 알파벳과 숫자들이 무작위로 섞여 있는 것을 볼 수 있습니다.
  • 인코딩 또는 암호화된 3가지 데이터를 이어붙이고, 중간에 .이 두군데에 들어가있습니다.
  • 이것을 Header,Payload,Verify Signature (헤더,페이로드,서명)으로 나뉩니다.
  • JWT.IO에서 인코딩된 예시를 볼 수 있습니다.

Payload : 페이로드

  • 이것을 디코딩하면 JSON 형식으로 여러 정보가 나타납니다.
  • 이 토큰을 누가 누구에게 발급하였는지, 이 토큰이 언제까지 유효한지,그리고 서비스가 사용자에게 이토큰을 통해 공개하기 원하는 내용이 나옵니다.
  • 사용자의 닉네임,서비스상의 레벨, 관리자 여부 등을 서비스 측에서 원하는 대로 담을 수 있습니다.
  • 이렇게 토큰에 담긴 사용자 정보등의 Data를 Claim 이라고 합니다.
  • 사용자가 로그인을 하고나서 받는 토큰에 이 정보들이 클레임이라는 것으로 실려옵니다.
  • 이것이 그 후 요청들마다 이번에는 사용자로부터 서버한테 보내집니다.
  • 사용자가 받아서 갖고 있는 토큰 자체에 이런 정보들이 들어있다면 서버가 요청때마다 일일이 DB에서 뒤져봐야 할 것들이 줄어듭니다.

    하지만 여기서 생각한것이 이렇게 중요한 것을 특별한 암호화도 아니고 인코딩 되어있는 것이라면, 사용자가 프로그래밍 언어를 이용하여 다시 디코딩하여 볼수도 있으며, 조작이 가능하지 않을까? 라는 생각이 들었습니다. 마음만 먹는다면 악용도 가능할 수도 있습니다. 예를들어 유효기간을 늘린다던가, 관리자 여부를 TRUE로 설정하여 관리자 권한으로 인가를 받을 수 있습니다.

    그래서 있는 것이 Header 와 Verify Signature 입니다.

Header : 헤더

  • 이 것을 디코딩 해보면 아래와 같이 나옵니다.

  • typ(type) : 토큰의 타입

    • 여기에는 무조건 JWT가 들어가야 합니다.
    • 즉, type이 JWT 이어야 JWT입니다.(고정값)
  • alg(Algorithm) : 알고리즘

    • 3번 서명값을 만드는데 사용될 알고리즘을 지정해줍니다.
    • HS256 등 여러 암호화 방식 중 하나를 지정할 수 있습니다.
  • 1번 Header 와 2번 Paylaod , 그리고 "서버에 감춰놓은 비밀값" 이 셋을 이 암호화 알고리즘에 넣고 돌리면 3번 서명값이 나오게 됩니다.

  • 즉, 이 암호화 알고리즘이라는 것이 한쪽 방향으로는 계산이 간으해도 반대로는 불가능하여, 서버만 알고 있는 비밀값을 찾을 방법이 없습니다.

  • 만약 토큰 값을 알고 2번 페이로드를 수정하여 유효한 3번 서버값이 나오려면 서버에 숨긴 "비밀키"를 알고 있어야 하기에 조작이 불가능합니다.
    - 서버는 요청에 토큰값이 실려들어오면 1,2번의 값을 "서버의 비밀 키"와 함께 돌려 봐서 계산된 결과 값이 3번 서명값과 일치하는 결과가 나오는지 확인합니다.

  • 3번 서명값과 계산 값이 일치하고, 유효기간도 지나지 않았다면 그 사용자는 로그인 된 회원으로 인가를 받습니다.

  • 그래서 서버는 사용자의 상태를 따로 기억해 둘 필요없이, 비밀값만 가지고 있으면 요청이 들어올 떄마다 토큰을 스캔하여 인가를 판별합니다.

  • 이처럼 시간에 따라 바뀌는 어떤 상태값을 갖지 않는 것을 "stateless하다" 라고 하고, 반대로 "Sessioin은 stateful하다" 라고 합니다.

    하지만 여기서 궁금했습니다. 그렇다면 무조건 Session 보다는 JWT을 써야 하지 않을까???
    저만 그런게 아닐까 생각합니다.

    하지만 세션을 대체하기에는 JWT가 큰 결점을 가지고 있습니다.

  • 세션처럼 stateful, 모든 사용자들의 상태를 기억하고 있다는 것은 구현하기 부담되고, 고려사항도 많지만 이게 되기만 한다면 기억하는 대상의 상태들을 언제든지 제어할 수 있다는 의미입니다.

  • 예를들어, 한 기기에서만 로그인 가능한 서비스를 만드는 경우 PC에서 로그인한 상태의 어떤 사용자가 핸드폰에서 또 로그인하면 PC에서는 로그아웃되도록 기존 세션을 종료할 수 있다는 것입니다.

  • 이미 줘버린 토큰을 다시 뻇을 수도 없고, 그 토큰의 발급 내역이나 정보를 서버가 어디 기록해서 추적하고 있는 것도 아니기 때문입니다.그래서 통제가 불가능합니다.

  • 심지어 악성프로그래머가 이 토큰을 가져갔는데, 이 토큰을 무효화할 방법도 없습니다. 때문에 실 서비스중에 JWT만으로 인가를 구현하는 곳은 생각보다 많지는 않습니다.

  • 물론 해결방법으로는 만료시간을 짧게 잛아서 토큰의 수명을 아주 짧게 부여합니다.

  • 물론 또 이렇게 짧게 준다고 하면 일정 시간 뒤에 또 재로그인을 할 상황이 발생하게 되어, 로그인을 하고나면 토큰을 2개를 줍니다.

    • 수명이 몇 시간이나 몇 분 이하로 짧은 access 토큰과, 꽤 길게, 보통 2주 정도로 잡혀 있는 refresh 토큰입니다.
    • 사용법 : access 토큰과 refresh 토큰을 발급하고 클라이언트에게 보내고 나서, refresh 토큰은 상응값을 DB에도 저장합니다. 고객은 access 토큰의 수명이 다하면, refresh 토큰을 보냅니다. -> 서버느 그것을 DB에 저장된 값과 대조해보고 맞다면 새 access 토큰을 발급해 줍니다.
      -> 이제 이 refresh 토큰만 안전하게 관리된다면 이게 유효할 동안은 access 토큰이 만료될 떄마다 다시 로그인할 필요없이 새로 발급을 받을 수 잇습니다.
    • 즉, 정리하면 인가를 받을 떄 쓰는 수명 짧은 토큰이 access 토큰이고,엑세스 토큰을 재발급 받을 떄 쓰는것이 refresh 토큰입니다.
    • 그렇게 하면은 중간에 엑세스 토큰이 탈취당해도 오래 쓰지는 못합니다.누군가를 강제로그 아웃을 시키려면 리플레시 토큰을 DB에서 지워버려 갱신이 안되게 하면 됩니다.
profile
블로그 이전합니다! https://jyyoun1022.tistory.com/

0개의 댓글