JWT 토큰

지송현·2023년 1월 31일
0

web

목록 보기
9/13
post-thumbnail

지난 글에서 인증과 인가의 개념에 대해 알아보았다. 이번엔 인증의 여러 방법(쿠키, 세션, 토큰) 중 토큰에 대해 알아보자.

토큰 인증

토큰 기반 인증은 클라이언트가 서버에 접속을 하면 해당 클라이언트에게 인증되었다는 의미로 '토큰'을 부여한다.
->
이 토큰은 유일하며 토큰을 발급받은 클라이언트는 이후 서버에 요청을 보낼 때 헤더에 이 토큰을 담아 보낸다.
->
서버는 클라이언트에게 받은 토큰을 서버에서 발급해준 토큰과 일치한지 검사한다. 일치하면 인증 완료

로그인 과정을 예로 들면 위와 같다.

  1. 사용자가 아이디와 비밀번호 입력
  2. 서버에서 클라이언트에게 유일한 토큰 생성 후 전달
  3. 클라이언트는 받은 토큰을 쿠키나 스토리지에 저장 후 서버에 인증이 필요한 요청을 할 때마다 해당 토큰을 헤더에 담아 요청
  4. 서버는 전달받은 토큰을 검증 후 응답
    -> 토큰에는 요청한 사람의 정보가 담겨있기 때문에 DB를 조회하지 않고 누구인지 확인할 수 있다.

다음 글에서 이야기하겠지만 기존의 세션기반 인증은 서버에서 사용자 정보를 저장하고 있어 인증을 위해 이를 조회하는 작업이 필요했는데, 토큰 기반 인증은 사용자 정보가 서버가 아닌 클라이언트에 저장되기 때문에 서버의 부담을 줄일 수 있다.

  • 특히 앱에서 가장 많이 사용된다. -> 앱에는 쿠키와 세션이 없기 때문

단점

  • 쿠키/세션과 다르게 토큰 자체의 데이터 용량이 커, 인증 요청이 많아질수록 네트워크 부하가 심해질 수 있다.
  • Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보는 담을 수 없다.
  • 토큰을 탈취당하면 대처하기 어렵다. (사용 기한 제한 등)

JWT

JWT는 json web token의 약자이다. 즉 인증에 필요한 정보들을 암호화시킨 JSON 토큰이다.

구조

JWT는 3가지(header, payload, signature)가 '.'로 구분되어 이루어져 있다.

토큰의 헤더는 typ(타입)과 alg(알고리즘) 두 가지로 구성된다.

  • typ : 토큰의 타입을 지정한다. ex) JWT
  • alg : signature을 해싱하는 알고리즘을 지정한다. ex) HS256(SHA256), RSA
{
	"alg" : "HS256",
    "typ" : JWT
}

PayLoad

페이로드에는 토큰에 담을 정보가 담겨있다. 이 정보의 한 조각을 클레임(claim)이라고 하고, name/value로 이루어져 있다.
이 클레임은 총 3가지로 나누어진다.

등록된 클레임(Registered Claim)

등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들로, 모두 선택적으로 작성하지만 사용할 것을 권장한다.
또, jwt를 간결하게 하기 위해 key는 3글자로 통일한다.

  • iss : 토큰 발급자(issuer)
  • sub : 토큰 제목(subject)
  • aud : 토큰 대상자(audience)
  • exp : 토큰 만료 시간(expiration), NumericDate 형식으로 되어있어야 함
  • nbf : 토큰 활성 날짜(not before), 이 날이 지나야 토큰이 활성화됨
  • iat : 토큰 발급 시간(issued at), 토큰 발급 이후의 경과 시간을 알 수 있음
  • jti : 토큰 식별자(jwt id), 중복 방지를 위해 일회용 토큰(Access Token) 등에 사용함

공개 클레임(Public Claim)

공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용된다. 출돌 방지를 위해 uri 포맷을 이용한다.

비공개 클레임(Private Claim)

비공개 클레임은 마찬가지로 사용자 정의 클레임이고, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.

Signature

서명은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다. 서명은 위에서 만든 헤더와 페이로드의 값을 Base64Url로 인코딩하고, 인코딩한 값을 secret key를 이용해 헤더에서 정의한 알고리즘으로 해싱하고, 그 값을 다시 Base64Url로 인코딩하여 생성한다.

-> 이렇게 생성된 토큰은 http 통신을 할 때 Authorization key의 value로 사용된다. 일반적으로 value 앞에 "Bearer"이 앞에 붙는다.

{
	"Authorizaion" : "Bearer {토큰}"
}

Access Token? Refresh Token?

여러 정보가 담긴 access token이 제3자에게 탈취당할 경우 위험할 수 있다는 것이 위 토큰 방식의 문제였다.

토큰이 발급된 이후, 서버에 토큰을 저장하지 않고 누구든지 그 토큰을 가지고 있다면 인증되기 때문에 토큰이 만료되기 전까진 누구나 접근 권한이 생긴다.

서버에서 토큰을 발급한 후에 삭제가 불가능하기 때문에 토큰의 만료기한을 잘 설정하는 것 외에는 대응할 방법이 없었다.

그러나 기한을 짧게하면 사용자의 편의성이 떨어지고 길게하면 보안상 위험이 커지는 것이다.

-> 이때 기한을 짧게 하면서 편의성을 떨어뜨리지 않는 방법이 Refresh Token이다.


access token, refresh token 모두 똑같은 jwt 토큰이다. 단지 역할이 다른데, access token은 접근에 관여하고, refresh token은 재발급에 관여한다.

간단하게 보면

  1. 서버가 토큰을 발급할 때 두 토큰을 모두 생성해 클라이언트에 보낸다.
  2. 서버는 refresh token을 db에 저장하고, 클라이언트는 두 가지 모두 저장한다.
  3. 클라이언트에서 서버에 요청을 보낼 때 access token을 보낸다.
  4. refresh token은 access token에 비해 긴 유효 기간을 가지기 때문에, 서버에 보낸 access 토큰이 만료되었을 경우 refresh 토큰을 서버로 전송한다.
  5. 서버는 db에 저장된 refresh 토큰과 비교해 일치하면 access 토큰을 재발급해준다.

정도이다. 구체적인 로직은 상황에 따라 바뀔 수 있다.


참고

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-JWTjson-web-token-%EB%9E%80-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC
https://mangkyu.tistory.com/56

profile
백엔드 개발자

0개의 댓글