소개
개발을 하다 보면 로그인 관련 기능을 만드는 경우가 많습니다.
로그인은 쿠키(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를 발생합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"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
로 인코딩 되어 있고 마침표(.)로 구분 된 세 부분으로 구성되어 있습니다.
1
2
3
4
5
[header.payload.signature]
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
tM-nO0TjFp-sF0-TYWjXKX_r9jEZvO1YWjKnWfIDWtM
- Header : Token 유형에 대한 메타데이터와 해당 콘텐츠를 보호하는 데 사용되는 암호화 알고리즘을 포함합니다.
- Payload(Claim Set) : 사용자의 ID 및 허용 된 권한과 같은 검증 가능한 보안 설명이 포함 되어 있습니다.
- Signature : Json Payload의 무결성을 확인하는 데 사용할 수 있는 암호화 알고리즘을 통해 생성 된 문자열 입니다.
아래 페이지에서 확인 가능 합니다.
Header
암호화 작업을 설명하는 매개변수가 포함 된 JSON 객체 입니다.
사용 중인 알고리즘과 Type을 기술합니다.
1
2
3
4
{
"alg": "HS256",
"type": "JWT"
}
1
2
3
4
5
6
[JSON 객체]
Base64URLSafe(UTF-8('{"alg": "HS256","type": "JWT"}'))
[직렬화]
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload
페이로드에는 엔티티(일반적인 사용자 정보)에 대한 설명과 Claim이라고 하는 추가 엔티티 속성이 포함 됩니다.
아래 속성들을 Claim Set
이라 부른다.
- Claim Set
- JWT에 대한 내용(토큰 생성자 정보, 생성 시간 등)
- 클라이언트와 서버 간 주고 받기로 한 값들로 구성
1
2
3
4
5
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
1
2
3
4
5
6
[JSON 객체]
Base64URLSafe(UTF-8('{"sub": "1234567890","name": "John Doe","admin": true}'))
[직렬화]
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
Signature
서명은 JWT를 보낸 사람이 누구인지 확인하고 메시지가 도중에 변경되지 않았는지 확인하는 데 사용됩니다.
1
2
3
4
5
6
7
8
9
10
[Signature]
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
tqQWhz5BCP(your-256-bit-secret-key)
)
[직렬화]
tM-nO0TjFp-sF0-TYWjXKX_r9jEZvO1YWjKnWfIDWtM
JWT 작동 원리
- 사용자가 ID와 Password를 입력하여 로그인을 시도합니다.
- 서버는 요청을 확인하고 Secret Key를 통해 Access Token을 발급합니다.
- JWT 토큰을 클라이언트에 전달합니다.
- 클라이언트에서 API을 요청할 때, 클라이언트가 Authorization Header에 Access Token을 담아서 보냅니다.
- 서버는 JWT Signature를 체크하고 Payload로 부터 사용자 정볼르 확인해 데이터를 반환합니다.
- 클라이언트의 로그인 정보를 서버 메모리에 저장하지 않기 때문에 토큰 기반 인증 메커니즘을 제공합니다.
인증이 필요한 경로에 접근 할 때 서버 측은 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을 만들 수 있습니다.
참고
- https://jwt.io/introduction
- https://supertokens.com/blog/what-is-jwt
- http://www.opennaru.com/opennaru-blog/jwt-json-web-token/