JWT(Json Web Token)

2023. 6. 2. 09:14Back-End/ASP.NET

소개

개발을 하다 보면 로그인 관련 기능을 만드는 경우가 많습니다.

로그인은 쿠키(Cookie), 세션(Sessions) 등으로 많이 구현하는데, 토큰(Token)을 사용하는 방법도 있습니다.

토큰을 사용하는 방법 중 JWT를 많이 사용하기에 JWT에 대해 정리하려고 합니다.

JWT

JWT(JSON Web Token)는 일반적으로 클라이언트(App FrontEnd)와 서버(App BackEnd)간에 정보를 공유하는 데 사용되는 개방형 산업 표준(RFC7519)입니다.

JWT는 Token 자체를 정보로 사용하는 Self-Contained 방식이며, 필요한 모든 정보를 Token에 저장하기 때문에 서버와의 커뮤니케이션에서 오버헤드를 최소화 할 수 있습니다.

또한 JSON Content(JWT Claim이라고도 함)을 변경 할 수 없도록 암호화(해싱)되어 있습니다.

아래는 Google에 로그인하면 Claim/JSON Payload가 포함 된 JWT를 발생합니다.

{
    "iss": "https://accounts.google.com",
    "azp": "1234987819200.apps.googleusercontent.com",
    "aud": "1234987819200.apps.googleusercontent.com",
    "sub": "10769150350006150715113082367",
    "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q",
    "email": "jsmith@example.com",
    "email_verified": "true",
    "iat": 1353601026,
    "exp": 1353604926,
    "nonce": "0394852-3190485-2490358",
    "hd": "example.com"
}

JWT 구조

JWT는 Base64Url로 인코딩 되어 있고 마침표(.)로 구분 된 세 부분으로 구성되어 있습니다.

[header.payload.signature]

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
tM-nO0TjFp-sF0-TYWjXKX_r9jEZvO1YWjKnWfIDWtM

  • Header : Token 유형에 대한 메타데이터와 해당 콘텐츠를 보호하는 데 사용되는 암호화 알고리즘을 포함합니다.
  • Payload(Claim Set) : 사용자의 ID 및 허용 된 권한과 같은 검증 가능한 보안 설명이 포함 되어 있습니다.
  • Signature : Json Payload의 무결성을 확인하는 데 사용할 수 있는 암호화 알고리즘을 통해 생성 된 문자열 입니다.

아래 페이지에서 확인 가능 합니다.

Header

암호화 작업을 설명하는 매개변수가 포함 된 JSON 객체 입니다.

사용 중인 알고리즘과 Type을 기술합니다.

{
    "alg": "HS256",
    "type": "JWT"
}
[JSON 객체]
Base64URLSafe(UTF-8('{"alg": "HS256","type": "JWT"}'))

[직렬화]
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Payload

페이로드에는 엔티티(일반적인 사용자 정보)에 대한 설명과 Claim이라고 하는 추가 엔티티 속성이 포함 됩니다.

아래 속성들을 Claim Set이라 부른다.

  • Claim Set
    • JWT에 대한 내용(토큰 생성자 정보, 생성 시간 등)
    • 클라이언트와 서버 간 주고 받기로 한 값들로 구성
{
    "sub": "1234567890",
    "name": "John Doe",
    "admin": true
}
[JSON 객체]
Base64URLSafe(UTF-8('{"sub": "1234567890","name": "John Doe","admin": true}'))

[직렬화]
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

Signature

서명은 JWT를 보낸 사람이 누구인지 확인하고 메시지가 도중에 변경되지 않았는지 확인하는 데 사용됩니다.

[Signature]

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
tqQWhz5BCP(your-256-bit-secret-key)
) 

[직렬화]
tM-nO0TjFp-sF0-TYWjXKX_r9jEZvO1YWjKnWfIDWtM

JWT 작동 원리

  1. 사용자가 ID와 Password를 입력하여 로그인을 시도합니다.
  2. 서버는 요청을 확인하고 Secret Key를 통해 Access Token을 발급합니다.
  3. JWT 토큰을 클라이언트에 전달합니다.
  4. 클라이언트에서 API을 요청할 때, 클라이언트가 Authorization Header에 Access Token을 담아서 보냅니다.
  5. 서버는 JWT Signature를 체크하고 Payload로 부터 사용자 정볼르 확인해 데이터를 반환합니다.
  6. 클라이언트의 로그인 정보를 서버 메모리에 저장하지 않기 때문에 토큰 기반 인증 메커니즘을 제공합니다.

인증이 필요한 경로에 접근 할 때 서버 측은 Authorization 헤더에 유효한 JWT 또는 존재하는지 확인한다.

JWT에는 필요한 모든 정보를 토큰에 포함하기 때문에 데이터베이스와 같은 서버와의 커뮤니케이션 오버 헤드를 최호화 할 수 있다.

Cross-Origin Resources Sharing(CORS)는 쿠키를 사용하지 않기 때문에 JWT를 채용 한 인증 메커니즘은 두 도메인에서 API를 제공하더라도 문제가 발생하지 않습니다.

일반적으로 JWT 토큰 기반의 인증 시스템은 위와 같은 프로세스로 이루어집니다. 처음 사용자를 등록 할 때 Access Token과 Refresh token이 모두 발급되어야 합니다.

JWT 장단점

장점

  • 보안 : JWT는 클라이언트나 해커가 수정하지 못하도록 보호하는 비밀(HMAC) 또는 공개/개인 키 쌍(RSA 또는 ECDSA)를 사용하여 디지털 서명됩니다.
  • 클라이언트에만 저장 : 서버에서 JWT를 생성하여 클라이언트로 보냅니다. 그런 다음 클라이언트는 모든 요청과 함께 JWT를 제출합니다. 이것은 데이터베이스의 공간을 절약 할 수 있습니다.
  • Efficient / Stateless : 데이터베이스 조회가 필요하지 않기 때문에 JWT를 빠르게 검증 할 수 있습니다. 이는 대규모 분산 시스템에서 특히 유용합니다.

단점

  • 취소 기능 : 자체 포함 된 속성 및 상태 확인 프로세스로 인해 JWT가 자연적으로 만료 되기 전에는 취소하기가 어렵습니다. 따라서 사용자를 즉시 차단하는 것과 같은 조치는 쉽게 구현 할 수 없습니다. (JWT 거부 및 블랙리스트로 취소 가능 하지만 어렵습니다.)
  • 사용자 정보 수정 : 취소 기능가 마찬가지로 발급 된 JWT는 수정이 불가능 하기 때문에 사용자의 정보를 데이터베이스에서 수정 했더라도 즉시 적용이 어렵습니다.
  • 1개의 Private 키 종속적 : JWT는 1개의 Private 키에 따라 달라집니다. 해당 키가 손상되면 공격자는 API 계층이 수락할 자체 JWT를 조작 할 수 있습니다.
  • 트래픽 : Stateless 애플리케이션에서 토큰은 거의 모든 요청에 대해 전송 되므로 데이터 트래픽이 증가 할 수 있습니다.

Claim

JWT는 Claim에 이름/값 쌍으로 여러 정보를 넣을 수 있습니다. JWT Claim에는 아래와 같은 두 가지 유형이 있습니다.

  • Registered : 등록 된 표준 Claim에 의해 정의되고 JWT 사양 타사 또는 외부 응용 프로그램과의 상호 운용성을 보장합니다.
  • Custom : 등록 되지 않은 public 또는 private claim으로 구성 됩니다.
    • Public Claim : JWT를 사용하는 사람들 마음대로 정의 할 수 있습니다. 그러나 충돌을 방지하려면 IANA JWT Registry에 등록해야 합니다.
    • Private Claim : Private으로 당사자 간의 정보를 공유하기 위해 생성 하는 맞춤형 Claim입니다.

Registered Claim

JWT 사양은 필수는 아니지만 상호 운용성을 위해 아래와 같이 권장하는 7개의 예약 Claim이 있습니다.

  • iss(발급자) : JWT 발행자
  • sub(주제) : JWT의 주제(사용자)
  • aud(청중) : JWT가 의도 된 수신자
  • exp(만료 시간) : JWT가 만료되는 시간
  • nbf(not before time) : JWT가 처리를 위해 수락 되어서는 안 되는 시간
  • iat(발행 시간) : JWT가 발행 된 시간. JWT의 나이를 결정하는 데 사용 할 수 있습니다.
  • jti(JWT ID) : 고유 식별자. JWT가 재생되는 것을 방지함

Custom Claim

사용자가 자신에게 맞는 Claim을 정의하고 Actions를 사용하여 토큰을에 추가 할 수 있습니다.

아래와 같이 사용 가능 합니다.

  • 사용자의 이메일 주소를 액세스 토큰에 추가하고 이를 사용하여 사용자를 고유하게 식별합니다.
  • Auth0 사용자 프로필에 저장 된 사용자 지정 정보를 ID 토큰에 추가합니다.

1. Public Claim

이름 및 이메일과 같은 일반 정보를 포함할 수 있는 공개 사용을 위한 사용자 지정 Claim을 만들 수 있습니다.

공개 Claim을 생성하는 경우 이를 등록하거나 네임스페이스를 통해 충돌 방지 이름을 사용하야 합니다. 아래는 IANA JWT Registry](https://www.iana.org/assignments/jwt/jwt.xhtml)에 등록 된 Public Claim 입니다.

  • auth_time
  • acr
  • nonce

2. Private Claim

개인 사용자 지정 Claim을 만들어 응용 프로그램과 관련 된 정보를 공유할 수 있습니다.

예를 들어 Public Claim 같은 경우 이름 및 이메일과 같은 일반적인 정보라면 Private Claim은 직원 ID, 부서 이름과 같은 더 구체적인 Claim을 만들 수 있습니다.

참고

'Back-End > ASP.NET' 카테고리의 다른 글

JWT의 Access Token과 Refresh Token  (0) 2023.06.02