JWT (⚠️ JMT아님 주의)

조혜인·2022년 8월 9일
0
post-thumbnail

하루에도 수십, 수백 명의 사용자가 서비스를 이용한다. 이 때 회원 가입 여부에 따라 혹은 관리자 여부에 따라 제공되는 서비스들이 달라진다. 따라서 서버는 동시다발적으로 서비스를 요청하는 사용자가 로그인을 한 상태인지 확인하여 다양한 서비스들을 사용할 수 있도록 응답해줘야한다. 이럴 때 필요한 것이 인증, 인가이다.


인증 & 인가란?

  • 인증(Authentication) : 사용자가 자기 계정을 사용을 하려고 할 때 로그인을 시켜준다.
  • 인가(Autorization) : 인증받은 사용자가 서비스를 사용하려고 할 때 서버가 인증을 받은 사람인지 확인하고 해당 서비스를 사용할 수 있게끔 해준다.

인증, 인가를 수행할 수 있는 방법

인증과 인가를 적용할 수 있는 다양한 방법들이 있는데 먼저 세션이다.

📌 세션

  • 사용자가 로그인에 성공하면 세션ID로 쿠기(브라우저에 저장되는 정보)로 저장하고 이 브라우저는 앞으로 다음 사이트에 요청을 보낼 때마다 함께 실어서 보낸다.
  • 세션ID를 이용해서 어떤 사용자가 서버에 로그인이 되어있음이 지속되는 것이 바로 세션이다.

하지만 이러한 세션에도 허점이 있는데,

📌 세션의 허점

  • 많은 사용자가 동시 접속을 할 경우 저장할 메모리가 부족해진다.
  • 서버에 문제가 있어 꺼져버리게 되는 경우 메모리가 휘발성이기 때문에 저장된 정보가 모두 날아갈 수 있다.

그렇다고 세션을 이용하지 않고 DB에 저장하자니 속도가 느려져서 고안해낸 것이 Redis나 MemCached같은 메모리형 데이터베이스 서버이다. 그런데 똑똑한 어느 개발자들이, 꼭 Redis나 MemCached 같은 서버들을 사용하지 않고도 가능하지 않을까? 라고 생각해서 만들어진 것이 토큰 방식JWT이다.


JWT(JSON Web Token)

  • JWT 홈페이지 : https://jwt.io/
  • JWT 서비스에서는 사용자가 로그인을 하면 토큰을 생성하여 건내준다.
  • JWT토큰은 암호화된 3가지 데이터를 이어붙인 것이다. 중간에 .(점)이 2군데 들어가있는 걸 확인할 수 있다.
  • JWT는 .(점)으로 구분하여 앞에서부터 Header, Payload, Verrify signature로 구분된다.

📌 Header

  • Header를 디코딩해보면 토큰의 type과 alg값이 들어있다.
    • type : jwt임으로 항상 "jwt" 값이 들어있다.
    • alg : Verify signature를 만드는데 사용될 알고리즘이 지정된다. HS256등 여러 암호화 방식 중 하나를 지정할 수 있다.

📌 Payload

  • Base64로 디코딩해보면 JSON형식으로 여러 정보들이 들어있다. 이 토큰이 누구로부터 누구에게 발급이 되었는지, 언제까지 유효한지, 서비스가 사용자에게 이 토큰을 공개하기 원하는 내용(닉네임, 관리자 여부 등)을 담을 수 있다. 이렇게 담긴 데이터들은 Claim이라고 한다.

📌 Verify signature

  • Header, Payload, 서버에 저장해놓은 비밀키를 해당 암호화 알고리즘에 넣고 돌리면 Verify signature값이 나온다.

  • 따라서 Header, Payload의 값들 중 한 글자만 바뀌어도 Verify signature값이 완전히 달라진다.

  • 서버는 받은 jwt토큰값을 서버에 저장되어있는 비밀키와 돌려 계산된 결과값이 Verify signature값과 일치하는 결과가 나오는지 확인한다. 결과 값이 일치하지 않으면 해커인 걸로 간주되어 요청이 거부된다.

  • Verify signature값이 일치하고 유효기간이 지나지 않았다면 해당 사용자는 인가를 받을 수 있다.

💡 시간에 따라 바뀌는 상태 값을 받지 않는 걸 stateless라고 하고(=> jwt), 반대로 바뀌는 상태값을 받는 걸 stateful이라고 한다.(=> 세션)

📌 jwt 결점

  • 세션처럼 stateful해서 모든 사용자들의 상태를 기억하고 있다면 기억하는 대상의 상태들을 언제든 제어할 수 있다. 예를 들어, 한 기기에서만 서비스 사용이 가능할 경우 세션에 저장된 정보를 이용하여 새로운 기기에서 로그인하였을 때 기존에 로그인된 기기를 로그아웃 시킬 수 있어야 한다. 그렇다고 JWT를 저장한다면 세션과 다른 바가 없어진다.

  • JWT 토큰을 해커에게 탈취당한 경우 해당 토큰을 무효화할 방법이 없다. => 이런 상황을 대비해서, 토큰의 만료시간을 가깝게 잡아 토큰의 수명을 짧게한다.

📌 jwt 결점 보완 프로세스(방법)

  1. 로그인을 할 때 accessToken, refreshToken 두 개를 나누어준다.

    • accessToken : 만료시간을 몇 시간 정도로 준다.
    • refreshToken : 만료시간이 꽤 길다. 보통 2주 정도이다.
  2. 두 토큰을 발급하고 클라이언트에게 보내고 나서 refreshToken은 DB에 저장한다.

  3. 회원은 access 토큰의 수명이 다하면 refresh토큰을 보낸다.

  4. 서버는 DB에 저장된 값과 대조해보고 맞다면 새 accessToken을 발급해준다.

refreshToken만 안전하게 관리된다면, accessToken이 만료될 때마다 다시 로그인할 필요 없이 새로 발급받을 수 있다. 하지만 accessToken이 만료되기 전까지 바로 차단할 수 없어, 2개의 토큰을 사용하더라도 JWT의 한계는 존재한다.

그런데, 자꾸 JWT가 JMT(존맛탱)처럼 보이는 이유는 뭐지..?🤔


참고

profile
코딩은 역시 재밌군

0개의 댓글