본문 바로가기

Fundamental/Web

JSON Web Token(JWT)을 소개합니다.

이 글은 아래 링크의 글을 번역한 글입니다.

https://jwt.io/introduction

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

 

 

JSON Web Token이 뭔가요?

JSON Web Token(JWT)는 당사자 간의 정보를 JSON 객체로 안전하게 전송하기 위한 간결하고 독립적인 방법을 정의하는 개방형 표준(RFC 7519)입니다. 이 정보는 디지털 서명되어 있기 때문에 검증되고 신뢰할 수 있습니다. JWT는 HMAC algorithm을 사용해 서명하거나, RSA/ECDSA 알고리듬을 사용한 공개/개인 키 쌍으로 서명할 수 있습니다.

 

JWT는 당사자 간 기밀을 제공하기 위해 암호화될 수 있지만, 우리는 서명된 토큰에 초첨을 맞추겠습니다.

서명된 토큰은 그 안에 포함된 클레임의 무결성을 검증하는 반면, 암호화된 토큰은 다른 당사자들로부터의 이러한 클레임을 숨깁니다.

공개/개인 키 쌍을 사용해 토큰에 서명했을 땐, 오직 개인키를 보유한 당사자만이 그 서명을 인증할 수 있습니다.


JSON Web Token을 언제 사용해야 하나요?

JSON Web Token이 유용한 몇 가지 시나리오가 있습니다.

 

1) 인증 : 인증은 JWT를 사용하는 가장 일반적인 시나리오입니다. 유저가 로그인을 하면, 각 후속 요청에는 JWT가 포함되어, 사용자는 이 토큰으로 허용된 경로, 서비스 및 리소스에 액세스할 수 있습니다. Single Sign On은 오버헤드가 작고 서로 다른 도메인에서 쉽게 사용할 수 있는 기능 때문에, 오늘날 JWT를 널리 사용하는 기능입니다.

 

2) 정보 교환 : JSON Web Token은 두 당사자 간에 정보를 안전하게 전송하기 위한 좋은 방법입니다. JWT는 공개/개인 키 쌍을 사용해 서명할 수 있으므로 보낸 사람이 누구인지 확인할 수 있기 때문입니다. 또한, 헤더와 페이로드를 사용해 서명을 계산할 때 내용이 변조되지 않았는지도 확인할 수 있습니다.


JSON Web Token의 구조는 어떻게 되어 있나요?

JSON Web Token은 (.)으로 구분해 세 가지 부분으로 구성됩니다.

 

1) 헤더(Header)

2) 페이로드(Payload)

3) 서명(Signature)

 

따라서, JWT는 일반적으로 다음과 같이 보입니다.

 

xxxxx.yyyyy.zzzzz

 

이제 각 부분을 나눠서 살펴봅시다.

 

1) 헤더(Header)

헤더는 일반적으로 두 가지 부분으로 나뉘어 구성됩니다.

 

- alg : HMAC SHA256 또는 RSA와 같이 서명에 사용된 알고리듬

- typ : 토큰의 유형

 

헤더의 예)

{
  "alg" : "HS256",
  "typ" : "JWT"
}

헤더는 Base64Url로 인코딩되어 JWT의 첫 번째 부분을 형성합니다.

 

2) 페이로드(Payload)

토큰의 두 번째 부분은 클레임을 포함하는 페이로드입니다. 클레임은 일반적으로 유저의 엔티티와 추가적인 데이터에 대한 정보입니다. 클레임에는 등록된 클레임, 공개 클레임, 개인 클레임의 세 가지 유형이 있습니다.

 

- 등록된 클레임(Registered Claim) : 이는 필수사항이 아니지만, 유용하고 상호 운용 가능한 클레임 집합을 제공하기 위해 권장되는 미리 정의된 클레임 집합니다. 그 중 일부로는 iss(토큰 발급자), exp(토큰 만료시간), sub(토큰 제목), aud(토큰 대상자) 등이 있습니다.

클레임의 이름은 JWT의 간결함을 위해서 길이 3의 String으로 되어 있습니다.

 

- 공개 클레임(Public Claim) : JWT를 사용하는 사람들에 의해 마음대로 정의될 수 있습니다. 하지만 충돌을 방지하려면 IANA JSON Web Token 레지스트리에 정의하거나, 충돌 방지 URI로 정의해야 합니다.

 

- 개인 클레임(Private Claim) : 당사자 간의 정보를 공유하기 위해 생성되며, 공개되지 않는 클레임입니다.

 

페이로드의 예를 들면 아래와 같습니다.

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

페이로드는 Base64Url로 인코딩 되어 JWT의 두 번째 부분으로 구성되어집니다.

 

서명된 토큰은 변조로부터 보호되지만 누구나 읽을 수 있습니다.
암호화되지 않은 경우, JWT의 페이로드나 헤더에 비밀 정보를 넣지 마세요.

 

3) 서명(Signature)

서명 부분을 만들려면 Base64Url로 인코딩된 헤더, 인코딩된 페이로드, 암호, 헤더에 지정된 알고리듬을 가져와서 서명해야 합니다.

 

예를 들어, HMAC SHA256 알고리듬을 사용하려는 경우 다음과 같은 방법으로 서명이 생성됩니다.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

 

서명은 메시지가 중간에 변조되지 않았음을 확인하는 데 사용되며, 개인 키로 서명된 토큰의 경우 JWT 발급자가 누구인지도 확인할 수 있습니다.

 

헤더, 페이로드, 서명을 함께 넣어보기

출력은 HTML과 HTTP 환경에서 쉽게 통과할 수 있는 점으로 구분된 3개의 Base64Url 문자열이며, SAML과 같은 XML 기반 표준에 비해 더 압축되어 있습니다.

 

다음은 헤더와 페이로드를 인코딩하고, 시크릿으로 서명된 값이 포함된 JWT를 보여줍니다.


JSON Web Token은 어떻게 동작하나요?

인증에서 사용자가 자격 증명을 사용하여 로그인하면 JSON 웹 토큰이 반환됩니다. 토큰은 자격 증명이므로 보안 문제를 방지하기 위해 많은 주의가 필요합니다. 일반적으로 토큰을 필요한 시간보다 길게 보관하면 안 됩니다.

또한 보안 부족으로 인해 중요한 세션 데이터를 브라우저 저장소에 저장해서는 안 됩니다.

사용자가 보호된 경로 또는 리소스에 액세스하고자 할 때마다 Authorization 헤더에 Bearer 스키마를 사용하여 JWT를 전송해야 합니다. 헤더의 내용은 다음과 같아야 합니다.

Authorization: Bearer <token>

 

이건 경우에 따라 무상태성(Stateless) 인증 메커니즘일 수 있습니다. 서버의 보호된 경로는 Authentication 헤더에서 유효한 JWT를 검사하고, JWT가 있는 경우 사용자는 보호된 리소스에 액세스할 수 있습니다. JWT에 서버에서 필요한 데이터가 포함되어 있는 경우, 특정 작업에 대한 DB 쿼리가 줄어들 수 있지만 항상 그렇지는 않습니다.

 

또한 Authentication 헤더로 토큰을 보내면, 쿠키를 사용하지 않으므로 Cross-Origin Resource Sharing(CORS) 문제가 발생하지 않습니다.

 

다음 다이어그램은 API 또는 리소스에 액세스하기 위해 JWT를 얻고 사용하는 방법을 보여줍니다.

  1. 응용 프로그램 또는 클라이언트가 인증 서버에 권한을 요청합니다.
  2. 권한이 부여되면, 인증 서버는 응용프로그램에 액세스 토큰을 반환합니다.
  3. 응용 프로그램은 액세스 토큰을 사용하여 보호된 리소스(예: API)에 액세스합니다.

서명된 토큰을 사용하면 토큰을 변경할 수 없는 경우에도 토큰에 포함된 모든 정보가 사용자나 다른 당사자에게 노출됩니다. 이것은 토큰 안에 비밀 정보를 넣으면 안 된다는 것을 의미합니다.


왜 JSON Web Token을 사용해야 하나요?

Simple Web Token(SWT), Security Assertion Markup Language Token(SAML)과 비교해 JWT의 장점을 이야기해 봅시다.

 

JSON은 XML보다 상세하지 않기 때문에 인코딩할 때 크키가 작아서 SAML보다 JWT가 더 간결합니다.

 

보안 측면에서 SWT는 HMAC 알고리즘을 사용하는 공유 비밀에 의해서만 대칭적으로 서명될 수 있습니다. 하지만 JWT와 SAML 토큰은 서명을 위해 X.509 인증서 형태로 공개/개인 키 쌍을 사용해 비대칭적으로도 서명할 수 있습니다. XML 전자 서명을 사용하여 XML에 서명하는 것은 JSON 서명에 비해 매우 어렵습니다.

JSON 파서는 객체에 직접 매핑하기 때문에 대부분의 프로그래밍 언어에선 일반적입니다. 반대로 XML에는 자연스러운 문서-객체 매핑이 없습니다. 이것은 SAML보다 JWT로 작업하기가 더 쉽다는 것을 뜻합니다.

실제 사용과 관련해선 JWT는 인터넷 규모로 사용됩니다. 이는 여러 플랫폼, 특히 모바일에서 클라이언트 측 JSON 웹 토큰을 쉽게 처리할 수 있음을 강조합니다.