[JWT] Session vs Token

JD_S·2022년 10월 16일
0

세션과 토큰 설명에 앞서 인증인가에 대한 이해를 해야한다.

인증(Authentication)

  • 유저를 확인하는 절차
  • ex) 로그인처럼 아이디랑 패스워드 등을 통해 권한이 주어진 사용자임을 인증받는 것

인가(Authorization)

  • 사용자 권한을 확인하는 절차
  • ex) 로그인하고 나서 자신의 계정으로만 할 수 있는 활동을 할 때 허가를 받는 것

세션

  • 서버에 로그인 되어있음이 지속되는 상태
  • 브라우저가 Session id쿠키를 저장하고 브라우저는 요청을 보낼때마다 이 쿠키를 보낸다. 서버는 확인하고 Session id가 유효하면 인가를 해준다.
  • 문제는 서버가 재부팅되어야 하는 상황이 오면 메모리에 있는 것들이 다 날아가게 된다. 이렇게 되면 로그인 상태를 유지하지 못한다.

JWT(JSON Web Token)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • 세션에서의 인가 문제를 부담없이 구현하기 위해 고안된 토큰방식
  • 브라우저에게 토큰을 주는데 서버는 토큰에 관한 것을 기억하고 있지 않는다.(stateless)
  • 인코딩 또는 암호화된 3가지 데이터를 이어붙임
  • header.payload.verify signature(헤더.페이로드.서명)
  • 페이로드
    • 토큰을 누가 누구에게 발급했는지, 언제까지 유효한지에 대한 것들이 담겨있다. 그리고 서비스가 사용자에게 토큰을 통해 공개하기 원하는 내용을 서비스 측에서 원하는 대로 담을 수 있다. 이렇게 토큰에 담긴 사용자 정보 등의 데이터를 Claim이라고 한다. 그래서 사용자가 로그인을 하고 나서 받는 토큰에 정보들이 클레임이라는 걸로 실려온다. 이후에 요청을 할 때마다 사용자로부터 서버한테 보내진다. 하지만 Base64로 인코딩이 되어있어 사용자가 자바스크립트로든 뭐로든 다시 디코딩해서 볼 수 있다면 악용될 소지가 있다. 이 문제를 해결하기 위해 헤더서명이 있는 것이다.

      Base64 : 8비트 이진 데이터(예를 들어 실행 파일이나, ZIP 파일 등)를 문자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로만 이루어진 일련의 문자열로 바꾸는 인코딩 방식을 가리키는 개념

  • 헤더
    • 디코딩을 하면 두 가지 정보가 담겨있다. 먼저 type, 토큰의 타입인데 여기에는 언제나 JWT가 들어간다. 다른 하나는 alg이다. 알고리즘의 약자인데 여기에는 서명 값을 만드는데 사용될 알고리즘이 지정된다.(중요)
      HS256 등 여러 암호화 방식 중 하나를 지정할 수 있다. 헤더페이로드 그리고 '서버에 감춰놓은 비밀 값' 이 셋을 이 암호화 알고리즘에 넣고 돌리면 서명값이 나온다. 서버는 요청에 토큰 값이 실려들어오면 1,2번의 값을 '서버 비밀 키'와 함께 돌려봐서 계산된 결과값이 3번 서명값과 일치하는 결과가 나오는지 확인을 한다. 그래서 누군가가 2번의 페이로드 값을 수정한다 할지라도 결과가 다르기 때문에 거부된다.
      3번 서명 값과 계산값이 일치하고 유효기간이 지나지 않을 때 사용자는 로그인 된 회원으로서 인가를 받는다.
  • 서명
    • 페이로드헤더 그리고 '서버에 감춰놓은 비밀 값'을 이용해 암호화 한 내용이 담겨 있다.

JWT의 결점

  • 세션처럼 stateful해서, 모든 사용자들의 상태를 기억하고 있는 건 구현하기 부담되고 고려사항도 많다. JWT는 토큰을 가지고 있지 않기 때문에 토큰의 발급 내역이나 정보들을 알지 못하기 때문이다. 그래서 통제할 수 없다.
  • 더 심각한 문제는 누군가 토큰을 탈취한다면 그 토큰을 무효화 시킬 수 있는 방법도 없다.

JWT의 보완 방식

  • 로그인을 하면 토큰을 두 개 준다.
    • access토큰 : 매번 인가를 받을때 쓰는 토큰으로 수명이 몇 시간이나 몇 분 이하로 짧다.
    • refresh토큰 : access토큰을 재발급 받을 때 쓰는 토큰으로 꽤 길게, 보통 수명은 2주 정도이다.
  • access토큰refresh토큰을 발급하고 클라이언트에게 보낸 후 refresh토큰 상응값을 DB에 저장한다. 클라는 access토큰의 수명이 다하면 refresh토큰을 보낸다. 서버는 DB에 저장된 값과 대조한 후 맞다면 새 access토큰을 발급한다. refresh토큰만 안전하게 관리 된다면 이게 유효할 동안은 access토큰이 만료될 때 마다 다시 로그인 할 필요 없이 새로 발급 받을 수 있다.
  • 그래서 access토큰이 탈취당한다고 한들 refresh토큰를 DB에서 지우면 토큰갱신을 막을 수 있지만 access토큰이 살아있는 동안에 막을 방법은 없다.

Reference

profile
Whatever does not destroy me makes me stronger.

0개의 댓글