JWT

lsy·2022년 11월 15일
0

JWT란?

JSON web Token의 약자로 권한 인증을 위해 사용한다.

세션은 서버 메모리 또는 DB에 저장하기 때문에 부담이 크다.

따라서, 여러 보안적인 요소를 더해서 서버에 저장하지 않고 유저를 인증하게 만든 방법이다.

전체적인 흐름

JWT의 발급과 사용의 전체적인 큰 흐름은 다음과 같이 이루어진다.

  1. 유저가 아이디와 패스워드를 사용해 서비스에 인증한다.
  2. 서버는 해당 유저를 식별하는 데 필요한 정보들을 모아 서명한 후 유저에게 지급한다.
  3. 유저는 해당 토큰을 저장해두었다가 유저 인증이 필요한 서비스에 http 헤더에 토큰을 첨부해 전송한다.
  4. 서버는 해당 토큰이 유효한지 판단하고 유효하면 클라이언트가 요청한 내용을 실행한다.

JWT 구조

JWT는 Header, Payload, Signature로 되어있다.

Header는 토큰의 타입과, 서명 알고리즘을 json으로 구성한다.

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload는 토큰 생성자의 정보, 생성 일시나 기타 클라이언트와 서버 간 주고 받기로 한 값들을 json으로 구성한다.

이런 속성들을 클레임(Claim)이라고 한다.

이 때 공식적으로 정의 되어 있는 속성을 등록된 클레임(Registered Claim)이라고 하고, 클라이언트와 서버 간 주고 받기로 한 기타 데이터들을 비공개 클레임(Private Claim)이라고 한다. 공개 클레임(Public Claim)도 존재한다. 어떤 사이트(https://www.iana.org/assignments/jwt/jwt.xhtml)에 JWT를 사용하는 사람들이 내가 어떤 사이트에서 이런 속성을 사용한다고 정의해놓은 것들인데, 크게 신경 쓰지 않아도 될 것 같다.

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Signature는 말 그대로 서명이다. 서명은 헤더에 정의된 알고리즘을 이용한다. 점(.)을 구분으로 해서 header와 payload를 secret key와 함께 서명한다. 이 때 header와 payload는 각각 base64encode 되어 있다.

Signature = HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

secret은 private key를 뜻한다.

세 개를 전부 합해서

base64UrlEncode(header).base64UrlEncode(payload).Signature

구조로 만들면 JWT 토큰이 된다.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

예를 들어 이런 값이 나오게 된다.

JWT 검증

지금까진 서버를 하나로 설명했지만, 아키텍쳐에 따라 검증을 두 가지로 나눌 수가 있다.

  1. 토큰을 만드는 인증 서버와, 토큰을 검증하는 리소스(서비스를 제공하는)서버가 따로 있는 경우
  2. 하나의 서버가 인증 서버와 리소스 서버를 겸임하는 경우

1번의 경우는 private key와 public key를 사용할 수 있다. (비대칭 키)

  1. 사용자에게 요청이 들어오면 인증 서버가 private key를 이용해 토큰을 발급한다.
  2. 사용자는 토큰을 저장하고 서비스를 요청할 때 리소스 서버에 토큰을 보낸다.
  3. 리소스 서버는 토큰의 서명을 인증 서버로부터 받은 public key를 이용해 해독해 검증한다.

2번의 경우는 하나의 secret key를 사용하면 된다. (대칭 키)

  1. 사용자에게 요청이 들어오면 서버는 secret key를 이용해 토큰을 발급한다.
  2. 사용자는 토큰을 저장하고 서비스를 요청할 때 서버에 토큰을 보낸다.
  3. 서버는 토큰의 서명을 갖고 있던 secret key를 이용해 해독해 검증한다.

JWT 보안

JWT는 클라이언트가 관리하기 때문에 탈취당할 수 있다.

JWT 토큰은 서버에서 관리하는 것이 아니기 때문에 탈취당하면 답이 없다. 따라서 유효 시간을 부여하는 방법으로 탈취에 대응한다.

그렇지만 이 유효 시간이 너무 짧으면 사용자가 계속 로그인을 하게 만들고, 너무 길면 보안에 취약해진다.

따라서 JWT를 두 가지로 나누는 방법을 사용한다. 하나는 Access Token으로 이전까지 설명하던 바로 접근에 관련한 토큰과 나머지 하나는 Refresh Token으로 재발급에 관여하는 토큰이다.

둘 다 똑같은 JWT로, 서버는 두 개의 토큰을 유저에게 발급하게 된다. 그리고 Refresh Token만 자신의 DB에 저장한다.

이후 유저는 요청마다 두 개의 토큰을 함께 보낸다. 유효 시간에 따라 여러 케이스들로 나눌 수 있겠다.

  • Access Token과 Refresh Token 둘 다 유효 시간이 남은 경우
    서버는 인증을 허가한다.

  • Access Token만 유효 시간이 남은 경우
    서버는 Refresh Token을 재발급한다.

  • Refresh Token만 유효 시간이 남은 경우
    서버는 Refresh Token을 자신의 DB를 조회 후 토큰이 존재한다면 Access Token을 재발급한다.

  • Access Token과 Refresh Token 둘 다 유효 시간이 남지 않은 경우
    서버는 에러를 발생시키고, 유저는 재 로그인해야 해서 새로 토큰을 발급 받아야 한다.


Reference

https://jwt.io/introduction
https://meetup.toast.com/posts/239
https://blog.miniorange.com/what-is-jwt-json-web-token-how-does-jwt-authentication-work/
https://stackoverflow.com/questions/60538047/jwt-private-public-key-confusion
https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-Access-Token-Refresh-Token-%EC%9B%90%EB%A6%AC-feat-JWT

profile
server를 공부하고 있습니다.

0개의 댓글