토큰과 JWT(JSON Web Token)

Joon·2021년 11월 22일
2

참고
https://jwt.io/
https://velopert.com/2389
https://covenant.tistory.com/201
https://www.youtube.com/watch?v=1QiOXWEbqYQ

이전 포스트 https://velog.io/@dev-joon/%EC%9D%B8%EC%A6%9DAuthentication%EA%B3%BC-%EC%9D%B8%EA%B0%80Authorization
에서는 인증과 인가, 세션과 쿠키와 그 장단점들을 살펴보았다. 이번에는 그 단점들의 Stateless 와 Stateful의 충돌을 없애기 위한 방법인 Token 기반 시스템을 살펴보자.

Token을 이용한 방법

토큰 기반 시스템의 존재이유는 바로 서버의 무상태성(Stateless)를 유지하기 위함이다. 상태정보를 저장하지 않으면, 서버는 클라이언트에서 들어오는 요청만으로 작업을 처리하기에 클라이언트와 서버의 연결고리가 없다. 이는 서버의 확장성(Scalability)를 높이는 효과를 가져온다.

  • 토큰 기반 시스템의 작동 원리
    1. 유저가 ID와 password로 로그인(인증)을 한다.
    2. 서버측에서 해당 유저정보를 조회하여 검증한다.
    3. 검증이 되었다면, 서버측에서 유저에게 signed Token을 발급한다. (signed = normally issued token by signature)
    4. 클라이언트는 전달받은 signed Token을 저장해두고, 서버에 요청을 할 때마다 해당 토큰을 HTTP Request Header에 포함하여 서버에 전달한다.
    5. 서버는 토큰을 검증하고, 요청에 응답한다.

장점

무상태성(Stateless)의 유지와 확장성(Scalability)
토큰을 클라이언트측에서 보관하기 때문에 서버의 입장에서는 무상태성을 유지할 수 있으며, 위에서 언급한 것과 같이 서버를 확장하기가 용이해진다. 또한 세션을 만약 서버측에 저장하고 있고, 서버를 여러대로 분산하여 요청을 처리하고 있다면, 세션DB를 따로 만든다던가 아니면 해당 요청을 세션ID가 위치한 서버로만 보낼 수 있도록 하는 등의 설정이 불필요해진다.

보안
사용자 정보를 클라이언트나 서버나 세션DB에 저장하지 않기 때문에 쿠키의 취약점으로 인해 발생하는 보안적인 문제가 사라진다.

Extensibility(확장성)
이 확장성은 Scalability와는 다른 확장성을 의미한다. Scalability는 서버의 확장이지만, Extensibility는 로그인(인증) 정보가 사용되는 분야의 확장을 의미한다. 토큰을 사용한다면, 다른 서비스에서도 한 서비스에서 설정된 권한을 공유할 수 있다.
OAuth로 예시를 들자면, 요즘 어플에 회원가입을 할 때 구글이나 카카오계정으로 로그인하기 기능같은 것들이 이에 해당한다고 볼 수 있다.

단점

데이터 증가에 따른 네트워크 부하
모든 요청에 대해 토큰이 전송되므로 토큰에 담기는 정보량에 따라 네트워크 부하가 증가한다.
탈취
토큰 자체에 모든 자체적인 정보를 담고 있기에 JWT가 만료시간 전에 탈취당할 시 서버에서 할 수 있는 조치가 없다.
Payload Base64 Encoding
Payload 자체가 암호화 된것이 아닌 Base64로 인코딩된 것이기 때문에 중간에 토큰을 탈취하여 디코딩하면 데이터를 볼 수 있다. 따라서 민감한 데이터는 Payload에 넣으면 안된다.
Stateless
JWT는 상태라는 것이 없기 때문에 한번 만들어지면 임의로 삭제하는 것이 불가능하다. 이를 위해 만료시간은 필수적으로 넣어주어야 한다.

JSON Web Token(JWT)

JWT란?

  • JSON Web Token (JWT) 은 웹표준 (RFC 7519) 으로서 두 개체에서 JSON 객체를 사용하여 가볍고 자가수용적인 (self-contained) 방식으로 정보를 안전성 있게 전달해준다.
  • 수많은 프로그래밍 언어 (C, Java, Python, C++, R, C#, PHP, JavaScript등등)에서 지원된다.
  • JWT Token은 해당 토큰에 대한 기본정보, 전달 할 정보, 그리고 토큰의 검증되었음을 증명하는 signature를 포함하고 있다.
  • HTTP Header에 넣는 방식으로도, URL의 Parameter로도 전달될 수 있기에 손쉽게 전달이 가능하다는 장점이 있다.
  • 단점으로는 해독하기가 굉장히 쉽기 때문에, JWT내에는 민감한 정보(유저 비밀번호등...)을 담으면 안된다.
  • Secret Key로 암호화/복호화하기에 Secret Key 보관에 신경을 써야한다.

JWT의 구성

  • Header(헤더), Payload(내용), Signature(서명)
    * Base64(Header).Base64(Payload).Base64(Signature)
    • .을 구분자로 하여 3가지 문자열로 구성된다.
    • Header와 Payload는 디코딩을 하면 평문으로 해독이 가능하다. 하지만 Signature부분은 복호화할 수 없다.

헤더(Header)

typ: Type of the Token: JWT
alg: Hashing Algorithem (ex. HMAC SHA256, RSA)
토큰을 검증할 때 사용되는 Signature 부분에서 알고리즘이 사용된다.

내용(Payload)

  • name/value 쌍으로 이루어져 있으며, 내용(Payload)에 위치한 속성들을 Claim이라고 부른다.
  • 클레임의 종류
    • 등록된(Registered) 클레임
    • 공개(Public) 클레임
    • 비공개(Private) 클레임

Registered Claim

서비스에 필요한 정보가 아닌, 토큰에 대한 정보를 담기 위해 이름이 이미 정해진 클레임이다.
Registered Claim의 사용은 모두 선택적으로 할 수 있다.
iss: 토큰 발급자 (issuer)
sub: 토큰 제목 (subject)
aud: 토큰 대상자 (audience)
exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어 있어야 한다.
nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념이다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않는다.
iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있다..
jti: JWT의 고유 식별자 - 주로 중복적인 처리를 방지하기 위하여 사용되며, 일회용 토큰(Access Token) 등에 사용된다.

Public Claim

사용자 정의 클레임으로 공개용 정보를 위해 사용된다. 충돌 방지를 위해 URI 포맷으로 사용한다.

Private Claim

등록된 클레임도 아니며, 공개 클래임도 아닌 서버와 클라이언트 사이에 임의로 지정한 정보를 저장하기 위해 만들어진 사용자 지정 클레임이다.

Signature(서명)

Header와 Payload는 암호화를 한 것이 아닌, 단순히 JSON 문자열을 base64로 인코딩한 것에 불과하기에 누구나 디코딩을 한다면 헤더와 페이로드의 내용을 볼 수 있다.
따라서 해커가 JWT를 탈취하여 수정한 후 서버로 보내는 등의 경우를 방지하기 위해 있는 것이 바로 Signature부분이다.

서명은 헤더의 (인코딩 값 + 정보의 인코딩 값)에 Secret Key로 Hash를 하여 생성한다.

그리고 이 모든 Header.Payload.Signature을 .중간자로 합쳐주면 JWT가 생성이된다.

Access Token / Refresh Token

Access Token이란

  • 리소스에 직접 접근할 수 있도록 하는 정보만 지닌다.
  • Refresh Token에 비해 짧은 만료 기간을 가진다.
  • 주로 세션에 담아 관리한다.

Refresh Token

해커가 토큰을 탈취할 경우, JWT의 토큰 만료시간을 짧게 지정하여 남용을 방지하는 조치를 취할 수 있지만, 이는 본래의 사용자 또한 사용할 수 없게 되는 부작용을 초래한다. 이를 방지하기 위해 만들어진 것이 바로 Refresh Token이라는 개념이다.

  • 새로운 Access Token을 발급하기 위한 정보를 지닌다.
  • 클라이언트가 Access Token이 없거나 만료될 시, Refresh Token을 통해 Auth Server에 요청하여 새로운 Access Token을 발급받을 수 있다.
  • Access Token에 비해 긴 만료 기간을 갖는다.
  • 외부에 노출되지 않도록 DB에서 관리한다.

과정


1. 유저가 ID와 password를 입력하여 서버에 로그인 인증을 요청한다.
2. 서버는 유저로부터 받은 정보를 확인 후, 헤더와 페이로드를 서버에 저장된 Secret Key를 지정된 알고리즘으로 돌려서 나온 값을 Access Token(JWT)와 Refresh Token로 발급한다.
3. 클라이언트는 JWT가 요구된 API를 요청할 때(장바구니 등등) Authorization header에 Access Token을 담아서 요청한다.
4. 서버는 JWT 토큰의 Signature를 체크하여 이상을 확인한다. 그 후 응답한다.
5. Access Token의 시간이 만료되면 클라이언트는 Refresh Token을 이용하여 새로운 Access Token을 발급받는다.

profile
한줄씩 완성해가는 개발 공부

0개의 댓글