JSON 웹 토큰
1. 개요
JSON 웹 토큰(JWT)은 헤더, 페이로드, 서명 세 부분으로 구성되며, 주로 사용자 인증 및 권한 부여에 사용되는 개방형 표준(RFC 7519)이다. 헤더는 토큰 유형과 서명 알고리즘을, 페이로드는 클레임(claim) 정보를 담고, 서명은 토큰의 무결성을 보장한다. JWT는 Base64url 인코딩을 사용하여 각 부분을 인코딩하고, 점(.)으로 연결하여 생성된다. JWT는 여러 프로그래밍 언어에서 구현되어 사용 가능하며, 만료 시간 설정, `alg` 필드 검증, 알고리즘 및 키 크기 선택 등에 주의하여 취약점을 예방해야 한다.
이미지 준비중입니다.
| 유형 | 인터넷 표준 |
|---|---|
| 약칭 | JWT |
| 개발 | IETF |
| 최초 게시일 | 2010년 12월 28일 |
| 버전 날짜 | 2015년 5월 |
| 위원회 | IEGS |
| 편집자 | Michael B. Jones Microsoft John Bradley Ping Identity Nat Sakimura NRI |
| 관련 표준 | JSON JSON 웹 암호화 (JWE) JSON 웹 서명 (JWS) |
| 도메인 | 데이터 교환 |
| 웹사이트 | JSON 웹 토큰 (JWT) 공식 웹사이트 |
| 기반 표준 | JSON JSON Web Encryption (JWE) JSON Web Signature (JWS) |
|---|
-
JSON -
JSON-LD
JSON-LD는 JSON 데이터를 RDF 모델로 표현하는 직렬화 방법으로, 컨텍스트를 활용해 JSON 속성을 온톨로지 개념에 연결하며 SEO, 의료 정보학, IoT 등 다양한 분야에서 활용되고 Schema.org, 구글 지식 그래프 등에서 중요한 역할을 한다. -
JSON -
BSON
BSON은 JSON과 유사한 이진 데이터 직렬화 형식으로, JSON보다 효율적인 저장 공간 활용과 빠른 검색 속도를 제공하며 다양한 데이터 유형을 지원하여 MongoDB의 주요 데이터 저장 및 전송 형식으로 사용된다. -
아이덴티티 관리 -
접근 제어
접근 제어는 컴퓨터 보안에서 주체의 대상 접근을 허가하거나 거부하는 행위 및 메커니즘으로, 정보의 기밀성, 무결성, 가용성을 보장하며 다양한 모델을 통해 구현되고 물리적/네트워크 환경에서 출입 통제 및 시스템 사용 제어를 포함하며 인증, 인가, 감사 단계를 거쳐 법규 및 표준 준수가 요구된다. -
아이덴티티 관리 -
아바타
아바타는 힌두교 용어에서 유래하여 신의 화신을 뜻하며, 온라인 환경에서 사용자를 나타내는 가상 신체를 의미하고, 게임, 소셜 미디어, 메타버스 등에서 사용자의 개성을 표현하고 소통하는 핵심 수단으로 활용되며 AR/VR 기술 발전과 함께 더욱 현실감 있는 사용자 경험을 제공한다. -
컴퓨터 접근 제어 -
로그인
로그인은 특정 페이지, 웹사이트 또는 응용 프로그램에 접근하기 위해 사용자 이름과 암호를 입력하여 시스템에 접근하는 절차이며, 1960년대 시분할 시스템과 1970년대 BBS에서 사용되기 시작했다. -
컴퓨터 접근 제어 -
SIM 카드
SIM 카드는 이동통신 장치에서 가입자 정보를 저장하고 네트워크를 인증하는 스마트 카드로, 가입자 식별 정보, 인증 정보, 전화번호부 등을 저장하며, 최근에는 내장형 eSIM으로 발전하고 있다.
2. 구조
JSON 웹 토큰(JWT)은 헤더(Header), 페이로드(Payload), 서명(Signature)의 세 부분으로 구성되며, 각 부분은 점(.)으로 구분된다. JWT는 Base64url 인코딩을 사용하여 각 부분을 인코딩하고, 점(.)으로 연결하여 생성한다.
```javascript
const token = base64urlEncoding(header) + '.' + base64urlEncoding(payload) + '.' + base64urlEncoding(signature)
```
JWT는 콤팩트하게 설계되었으며, URL에 안전하고, 특히 웹 브라우저에서 싱글 사인온(SSO)을 수행하는 경우 사용하기 편리하다. 토큰에는 일반적으로 인증 프로바이더나 서비스 제공자가 인증한 사용자 식별 정보뿐만 아니라, 각 서비스에 필요한 정보도 저장된다. JWT는 JSON 기반의 오픈 표준인 JSON Web Signature영어(JWS) 및 JSON Web Encryption영어(JWE)에 기반하고 있다.
2.1. 헤더 (Header)
헤더는 서명 생성에 사용되는 알고리즘을 식별한다. 일반적으로 사용되는 암호화 알고리즘은 HMAC와 SHA-256 (HS256), RSA 서명과 SHA-256 (RS256)이다. JWA (JSON 웹 알고리즘) RFC 7518은 인증과 암호화 모두를 위해 더 많은 알고리즘을 소개한다.
예시는 다음과 같다.
2.2. 페이로드 (Payload)
페이로드는 토큰에 담을 정보, 즉 클레임(Claim)을 포함하는 JSON 객체이다. JWT 사양은 토큰에 일반적으로 포함되는 7개의 등록된 클레임 이름(표준 필드)을 정의한다. 토큰의 목적에 따라 사용자 지정 클레임 또한 일반적으로 포함된다.
다음은 표준 발행 시간 클레임(iat영어)과 사용자 지정 클레임(loggedInAs영어)을 보여주는 예시이다.
```json
{
"loggedInAs" : "admin",
"iat" : 1422779638
}
```
JWT (JSON 웹 토큰)에서는 토큰 내에 임의의 정보(클레임)를 보관할 수 있다. 예를 들어, 서버는 클라이언트에 대해 "관리자로 로그인됨"이라는 정보를 포함한 토큰을 생성할 수 있으며, 클라이언트는 해당 토큰을 자신이 관리자로서 로그인되었음을 증명하는 데 사용할 수 있다.
2.3. 서명 (Signature)
토큰을 안전하게 확인한다. 서명은 Base64url 인코딩을 이용하여 헤더와 페이로드를 인코딩하고 이 둘을 점(.) 구분자로 함께 연결시킴으로써 계산된다. 해당 문자열은 그 뒤 헤더에 규정된 암호화 알고리즘(이번 경우에는 HMAC-SHA256)에 유입된다. Base64url 인코딩은 base64와 비슷하지만 각기 다른 영숫자를 사용하며 패딩(padding)은 제외한다.
```javascript
HMAC-SHA256(
secret,
base64urlEncoding(header) + '.' +
base64urlEncoding(payload)
)
2.4. 전체 구조 예시
위의 데이터와 "secretkey" 시크릿은 다음의 토큰을 생성한다:
이 결과 토큰은 HTML과 HTTP 환경에서 쉽게 파싱될 수 있다.
| 헤더 | 서명 생성을 위해 사용될 알고리즘을 식별한다. | |
|---|---|---|
| 페이로드 | 일련의 클레임을 포함한다. JWT 사양은 토큰에 일반적으로 포함되는 표준 필드인 7개의 등록 클레임 이름(Registered Claim Names)을 정의한다. 토큰의 목적에 따라 사용자 지정 클레임 또한 일반적으로 포함된다. | |
| 서명 | 토큰을 안전하게 확인한다. 서명은 Base64url 인코딩을 이용하여 헤더와 페이로드를 인코딩하고 이 둘을 점(.) 구분자로 함께 연결시킴으로써 계산된다. 해당 문자열은 그 뒤 헤더에 규정된 암호화 알고리즘(이번 경우에는 HMAC-SHA256)에 유입된다. Base64url 인코딩은 base64와 비슷하지만 각기 다른 영숫자를 사용하며 패딩(padding)은 제외한다. |
3. 표준 필드
JWT 표준(RFC 7519)은 페이로드에 포함될 수 있는 표준 클레임들을 정의한다. JWT는 토큰 내에 임의의 정보(클레임)를 보관할 수 있으며, 예를 들어 서버는 클라이언트에 대해 "관리자로 로그인됨"이라는 정보를 포함한 토큰을 생성할 수 있다. 클라이언트는 해당 토큰을 자신이 관리자로서 로그인되었음을 증명하는 데 사용할 수 있다. 토큰은 당사자 중 한쪽(일반적으로 서버) 또는 양쪽(다른 한쪽은 공개 키를 제공)의 비밀 키에 의해 서명되며, 발행된 토큰이 정품인지 확인할 수 있다.
JWT 토큰은 콤팩트하게 설계되었으며, URL에 안전하며, 특히 웹 브라우저에서 싱글 사인온(SSO)을 수행하는 경우 사용하기 편리하다. 토큰에는 일반적으로 서비스 제공자가 인증한 사용자 식별 정보가 저장될 뿐만 아니라, 각 서비스에 필요한 정보도 저장된다.
JWT는 다른 JSON 기반의 오픈 표준인 JWS(, RFC 7515) 및 JWE(, RFC 7516)에 기반하고 있다.
표준 클레임 필드 외에 일반적으로 사용되는 헤더 필드가 있다.
3.1. 등록된 클레임 (Registered Claims)
Registered Claims영어
JWT(JSON 웹 토큰)의 표준으로 등록된 클레임은 다음과 같다.
| 코드 | 명칭 | 설명 |
|---|---|---|
iss | 발급자(Issuer영어) | 토큰 발행자를 식별한다. |
sub | 주체(Subject영어) | 토큰의 주체를 식별한다. |
aud | 대상자(Audience영어) | 토큰이 대상으로 하는 수신자를 식별한다. 토큰을 처리하는 측에서는 이 값으로 자신을 식별해야 한다. aud 클레임이 존재하는데, 값으로 자신을 식별하지 않으면 JWT는 거부되어야 한다. |
exp | 만료 시간(Expiration Time영어) | JWT가 처리에 대해 수락해서는 안 되는 만료 시간을 식별한다. 값은 1970-01-01 00:00:00Z 이후의 초를 나타내는 정수 또는 십진수인 NumericDate여야 한다. |
nbf | 유효 전(Not Before영어) | JWT가 처리를 위해 수락되기 시작하는 시간을 식별한다. 값은 NumericDate여야 한다. |
iat | 발급 시간(Issued At영어) | JWT가 발급된 시간을 식별한다. 값은 NumericDate여야 한다. |
jti | JWT ID | 다른 발급자들 사이에서도 토큰의 대소문자를 구분하는 고유 식별자이다. |
현재 등록된 클레임 이름 목록은 IANA JSON 웹 토큰 클레임 레지스트리에서 얻을 수 있다.
3.2. 일반적인 헤더 필드
JWT영어의 헤더에서 일반적으로 사용되는 필드는 다음과 같다.
| 코드 | 이름 | 설명 |
|---|---|---|
| `typ` | 토큰 유형 | https://www.iana.org/assignments/media-types/media-types.xhtml IANA 미디어 유형으로 설정해야 한다. 일반적으로 `JWT`이다. |
| `cty` | 콘텐츠 유형 | 중첩 서명 또는 암호화가 사용되는 경우 `JWT`로 설정하는 것이 좋다. 그렇지 않으면 이 필드는 생략한다. |
| `alg` | 메시지 인증 코드 알고리즘 | 발급자는 토큰의 서명을 확인하기 위해 자유롭게 알고리즘을 설정할 수 있다. 그러나 일부 지원되는 알고리즘은 안전하지 않다. |
| `kid` | 키 ID | 클라이언트가 토큰 서명을 생성하는 데 사용한 키를 나타내는 힌트이다. 서버는 이 값을 파일의 키와 일치시켜 서명이 유효하고 토큰이 인증되었는지 확인한다. |
| `x5c` | x.509 인증서 체인 | 토큰 서명을 생성하는 데 사용된 개인 키에 해당하는 RFC4945 형식의 인증서 체인이다. 서버는 이 정보를 사용하여 서명이 유효하고 토큰이 인증되었는지 확인한다. |
| `x5u` | x.509 인증서 체인 URL | 서버가 토큰 서명을 생성하는 데 사용된 개인 키에 해당하는 인증서 체인을 검색할 수 있는 URL이다. 서버는 이 정보를 검색하여 서명이 인증되었는지 확인한다. |
| `crit` | 중요 | 토큰을 유효한 것으로 수락하기 위해 서버가 이해해야 하는 헤더 목록이다. |
4. 이용
JWT는 주로 사용자 인증 및 권한 부여에 사용된다. 사용자가 로그인하면 서버는 JWT를 생성하여 클라이언트에 반환한다. 클라이언트는 이후 요청 시 JWT를 `Authorization` HTTP 헤더에 담아 전송한다(Bearer 스키마 사용). 서버는 JWT를 검증하여 사용자를 인증하고, 필요한 정보를 추출하여 요청을 처리한다.
JWT는 서버에 인증 상태를 유지하지 않는 무상태 인증 방식이다. JWT에는 인증에 필요한 모든 정보가 포함되어 있어 데이터베이스 쿼리를 줄일 수 있다. JWT는 URL에 사용하기 안전하며, 웹 브라우저에서 싱글 사인온(SSO)을 수행하는 경우 사용하기 편리하다.
JWT는 JSON Web Signature영어(JWS) 및 JSON Web Encryption영어(JWE)에 기반하고 있다.
사용자가 서버에 로그인을 시도할 때, 기존의 세션 기반 인증 방식은 쿠키를 통해 세션 ID를 반환하지만, JWT에서는 토큰이 반환되어 로컬에 저장하여 사용한다(주로 Web storage영어가 사용된다. 세션 ID처럼 쿠키를 사용하는 경우도 있다).
인증 과정에서 사용자가 성공적으로 로그인하면 종종 JWT가 반환된다. 이 토큰은 HTTP-only 쿠키와 같은 보안 메커니즘을 사용하여 클라이언트에 전송해야 한다. JWT를 로컬 또는 세션 스토리지와 같은 브라우저 스토리지 메커니즘에 로컬로 저장하는 것은 권장되지 않는다. 이는 클라이언트 측에서 실행되는 JavaScript(브라우저 확장 포함)가 이러한 스토리지 메커니즘에 접근하여 JWT를 노출하고 보안을 손상시킬 수 있기 때문이다.
서버는 클라이언트에 대해 "관리자로 로그인됨"이라는 정보를 포함한 토큰을 생성할 수 있다. 클라이언트는 해당 토큰을 자신이 관리자로서 로그인되었음을 증명하는 데 사용할 수 있다. 토큰은 당사자 중 한쪽(일반적으로 서버) 또는 양쪽(공개 키를 제공)의 비밀 키에 의해 서명되며, 발행된 토큰이 정품인지 확인할 수 있다.
5. 구현체
6. 취약성
JSON 웹 토큰(JWT)은 세션 상태를 포함할 수 있지만, JWT 만료 전에 세션을 무효화해야 하는 경우 서비스는 토큰만으로 유효성을 신뢰할 수 없다. 토큰에 저장된 세션이 해지되지 않았는지 확인하려면 데이터 저장소에 대해 확인해야 하며, 이로 인해 JWT의 주요 장점인 무상태성이 훼손된다.
보안 컨설턴트 팀 맥클린(Tim McLean)은 일부 JWT 라이브러리에서 `alg` 필드를 사용하여 토큰을 잘못 검증하는 취약점을 보고했다. 가장 흔하게 `alg=none` 토큰을 허용하는 방식이었다. 이러한 취약점은 패치되었지만, 맥클린은 유사한 구현 혼란을 방지하기 위해 `alg` 필드를 완전히 사용 중단할 것을 제안했다. 그럼에도 불구하고 새로운 `alg=none` 취약점이 여전히 발견되고 있으며, 2018-2021년 기간 동안 이로 인해 네 개의 CVE가 등록되었다.
적절한 설계를 통해 개발자는 다음과 같은 예방 조치를 취하여 알고리즘 취약점을 해결할 수 있다.
* JWT 헤더만으로 검증하지 말 것
* 알고리즘을 숙지할 것 (alg영어 필드에만 의존하지 말 것)
* 적절한 키 크기를 사용할 것
소프트웨어 보안 설계자 커트 로다머(Kurt Rodarmer)는 암호화 서명 키와 관련한 JWT의 추가적인 설계적 취약성, 그리고 라이브러리의 JSON 파서가 공격에 노출되는 중대한 취약성을 지적한다.
2017년에는 여러 JWT 라이브러리에서 무효한 타원 곡선 공격에 취약한 것으로 밝혀졌다.
JWT는 상태 비저장이므로 JWT 자체로는 토큰을 무효화할 수 없다. 기존 세션처럼 서버에 상태를 유지하면 가능하지만, 그 경우 상태 비저장의 이점은 사라진다.