이 글에서는 JWT를 사용하는 이유와 JWT 사용 과정에 대해 정리해보았다.

JWT를 사용하는 이유?

이전 글에서 Cookie와 Session을 사용해서 로그인 상태를 유지하는 방식을 정리했었다.

img

쿠키는 브라우저에 사용자의 아이디값을 그대로 보관하기 때문에 안전하지 않다. 누군가 해당 정보(유저 ID : 1)를 탈취할 수 있다. 반면 세션의 경우, 서버에 저장되어 보안 안전하다. 사용자가 로그인 후에 서버에서 세션 아이디(암호화된 사용자 ID)를 발급하고 이를 사용자에게 전달한다. 세션 ID가 탈취되어도 유저 정보를 알아내기 어렵다.

하지만 세션도 몇 가지 문제가 있었다. 다중 서버일 때 세션 ID를 공유하지 못하기에 Scale-out하기 어려워진다. 또한, 매 접속 시마다 DB 조회를 해야되기에 오버헤드가 발생한다.

이러한 쿠키와 세션의 대안으로 JWT 방식이 등장하였다. JWT는 쿠키처럼 토큰 방식의 장점(Scale-out 쉬움, DB 조회X)을 가지면서도, 세션처럼 보안 성능을 가져갈 수 있다.

JWT란?

우선 JWT는 인증에 필요한 정보들을 암호화시킨 JSON 토큰이다. (암호화된 토큰이지만, 보안 기능은 없다! 이유는 아래에..!) 즉, JWT는 토큰 기반 로그인 방식이다. JWT를 HTTP 헤더에 담아 서버가 클라이언트를 식별하여 로그인한다.

JWT는 아래 세가지로 이루어져 있다.

  • header : 암호화 알고리즘, 토큰 타입
  • payload : 토큰에 담아 전송할 데이터
  • signature : 인코딩된 헤더와 페이로드를 합쳐 비밀키로 해싱한 값. 이 서명(signature)으로 데이터의 무결성을 입증하는데 사용한다. (헤더나 페이로드가 변경되었는지 알 수 있음)

JWT는 아래와 같은 과정을 거쳐 로그인을 하게 된다.

img

  1. 사용자는 ID/PW로 로그인합니다.
  2. 서버는 비밀 키를 사용해 JWT 발급합니다.
  3. 이 JWT를 사용자에게 전달하고, 사용자는 로컬 스토리지에 저장합니다.
  4. 사용자는 이후 요청부터는 헤더에 JWT를 담아 전송합니다.
  5. 서버에서 JWT를 검증합니다.
    • 검증이 된 토큰일 경우, 서버에서 요청에 따른 응답 전송합니다.

이처럼 JWT는 쿠키처럼 토큰 방식이기에 Scale-out도 쉽고, DB 조회도 하지 않으므로 오버헤드가 적게 든다. 뿐만 아니라 별도의 세션 저장소도 필요하지 않다.

주의 : JWT는 암호화가 아닌, 위조 방지를 위한 토큰이다

JWT는 데이터의 무결성을 확인하는 용도이지, 데이터를 보호하지는 못한다..! 복호화를 해서 토큰값이 위조되지 않았는 지 확인하는 용도이기 때문에 엄격한 암호화를 하지는 않는다. 따라서 JWT 토큰에 중요한 정보를 노출시키면 안된다. 해당 토큰의 만료 기한까지는 JWT 토큰이 탈취당해도 서버측에서 방어할 방법이 없다. 이에 대한 대안으로 Access Token과 Refresh Token을 함께 사용할 수 있다.

Access Token과 Refresh Token을 함께 쓰기

우선 Access Token에는 필요한 정보를 담되 만료 기간을 짧게 정한다. 그리고 Refresh Token은 긴 만료 기간을 가지되 DB 등 저장소에 보관한다. 로그인된 유저마다 Refresh Token을 저장해둔다. 사용자가 Refresh Token을 전송해왔을 때 저장소의 Refresh Token와 비교하여 검증한다.

  • Access Token : 로그인 상태를 유지하기 위한 토큰, 짧은 만료 기간
  • Refresh Token : Access Token을 재발급받기 위한 토큰, 긴 만료 기간

이 방식으로 사용자 정보가 담긴 Access Token으로 API를 요청하다가, 이 토큰이 만료될 경우 Refresh Token을 확인하여 Access Token을 재발급한다. 그리고 이 Refresh Token 마저도 만료될 경우, 새롭게 로그인해야한다.

Access Token과 Refresh Token을 함께 사용하면 아래와 같은 과정을 거친다.

img

  1. 사용자가 로그인(ID, PW)을 한다.
  2. 서버에서 회원 DB를 통해 회원이 맞으면, JWT 토큰을 발행한다.
  3. 이후 사용자는 헤더에 Access Token을 담아서 API 요청을 한다. 서버는 토큰이 정상임을 확인하면, 해당 요청에 맞는 처리를 진행한다.
  4. Access Token의 만료 기간이 지난 후에는, 서버가 요청을 처리하지 않고 만료되었다고 알린다. 그러면 사용자는 Refresh Token을 전송한다.
  5. 서버는 Refresh Token을 검증한 후, 토큰을 재발급하여 사용자에게 전송한다.

이후에 Refresh Token 또한 만료될 경우, 사용자는 다시 로그인을 해야 한다.

여기까지 Access Token과 Refresh Token에 대해서 알아보았다. 다음 글에서는 Refresh Token을 어디에 저장하는 게 좋을 지 정리해볼 예정이다⚡