본문 바로가기

개념및 용어

JSON Web Token(JWT)

참고자료: https://jwt.io/introduction/

 

JSON Web Token 소개

JSON Web Token 이 뭔지 간단히 알아 보기 위해 기사를 하나 찾아서 번역해 보았습니다.  

기사 번역과 스펙 해석이 약간 섞여 있기 때문에 기사 원문은 꼭 확인하시길 바랍니다.  

JSON Web Token 이란 ?

JSON Web Token은 참여자들간에 정보를 보안적으로 전달하기 위해 JSON 객체를 사용하는 공개 표준(RFC 7519)이다. 이 정보는 디지털로 서명되기 때문에 검증될 수 있으며 신뢰받을 수 있다. JWT는 시크릿(HMAC 알고리즘)이나 RSA 또는 ECDSA를 사용하는 public/private 키 쌍을 사용해서 서명될수 있다.

 

JWT 가 참여자들간 기밀을 제공하기 위해 암호될 수 도 있지만 우리는 서명된 토큰(signed token)에 대해 더 알아볼 것이다. 서명된 토큰들은 그 토큰내에 포함된 클레임(claim)들의 무결성을 검증할 수 있는데 반해 암호화된 토큰들은 다른 참여자들로부터 그들의 클레임을 숨기는 것이다. public/private 키 쌍을 사용해서 토큰들이 서명되면, 이 서명은 서명에 사용된 private 키를 보유하고 있는 참여자만이 서명을 했던 참여자라는 것을 보증하게된다. 

언제 JSON Web Token을 사용하면 될까?

다음은 JSON Web Token 사용되기에 유용한 시나리오들이다. 

  • 인가(Authorization): JWT를 사용하는 가장 흔한 시나리오. 한번 사용자가 로그인 되면 이 후, 매요청마다 JWT를 포함시킬 것이다. JWT를 이용해서 사용자에게  허용되는 경로나 서비스 또는 리소스들을 제공하는 것이다. Single Sign On 에서 요즘 많이 사용하는 기능인데  작은 오버헤드와 다른 도메인간 쉽게 사용될 수 있기 때문이다. 
  • 정보교환: JSON Web Token은 참여자들간 보안적으로 정보를 전송하기 위한 좋은 방식이다. JWT가 서명될 수 있기 때문인데, 예를들어 public/private 키 쌍을 사용하면, 여러분은 전달자가 누구인지 확인할 수 있기 때문이다. 추가적으로 서명에는 헤더와 페이로드를 사용해서 계산되기 때문에 컨텐츠가 위조되지 않았다는 것을 입증할 수 있다. 

JSON Web Token 구조

What is the JSON Web Token structure?

JSON Web Token은 3개의 파트로 구성되며 "."(dot) 으로 구분되는 각 파트는 다음과 같다.

  • Header
  • Payload
  • Signature

JWT 보통 아래와 같은 형태로 되어 있다.

xxxxx.yyyyy.zzzzz

각 파트별로 알아보자. 

Header

헤더는 보통 2개의 파트로 구성되는데 값이 "JWT" 인 토큰 유형과 HMAC SHA256 이나 RSA 와 같이 사인하는데 사용되는 알고리즘으로 되어 있다. 

예를들면 아래와 같다

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

이 JSON은 JWT 의 첫번째 파트로서 Base64Url 으로 인코딩된다. 

Payload

토큰의 두번째 파트는 페이로드인데, 클레임(claim)들을 포함하고 있다. 클렘임은 엔티티들(보통 사용자)에 대한 설명 문구들과 부가적인 데이터로 되어 있다. 클레임에는 registered, public, private 와 같이 3가지 유형이 있다. 

  • Registered claims: 필수 값은 아니지만 상호 운용에 유용한 클레임들로 사용이 권장된다. iss(issuer), exp(pxpiration time), sub(subject), aud(audience) 등이 있으며 추가적인 것은 "https://tools.ietf.org/html/rfc7519#section-4.1" 에서 확인할 수 있다. - 클레임 이름들은 JWT 와 같이 3글자로만 이루어져 있다. 
  • Public claims: 이 클레임들은 JWT 를 사용하는 사람들이 임의로 정의할 수 있으나 충돌을 피하기 위해서는 새로운 클레임 이름들은 IANA "JSON Web Token Claims" 레지스트리에 등록되어 있거나 충돌방지 네임스페이스를 포함하는 URI 처럼 정의되어야 한다.  
  • Private claims: 커스텀 클레임들로 이 클레임들 사용에 대해 동의한 참여자들간의 정보를 공유하기 위해 생성된다. registered 나 public 클레임에 포함되지 않는다. 스펙을 참고하여 덧 붙이자면 public 클레임들과 달리 충돌하기 쉽기 때문에 주의깊에 사용되어야 한다. 

페이로드의 예는 다음과 같다. 

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

페이로드는 JSON Web Token 의 두번째 파트로 Base64Url 로 인코딩 된다.

서명된 토큰은 위조가 되지 않도록 되어 있으나 누구나 읽을 수  있는 정보 이므로  JWT 의 헤더 요소나 페이로드 내에 시크릿 정보를 넣을 경우 반드시 암호화 해야한다. 

 

Signature

시그니쳐 파트를 생성하려면, 인코딩 된 헤더, 인코딩 된 페이로드, 시크릿 헤더에 기술된 알고리즘을 가져와서 서명한다. 

예를들어 HMAC SHA256 알고리즘을 사용하고 싶다면, 시그니처는 아래와 같은 방식으로 생성될 것이다. 

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

시그니쳐는 도중에 메시지가 변경되지 않았다는 것을 검증하기 위해 사용되는 것으로, 프라이빗 키로 서명된 토큰을 사용할 경우 JWT 전송자는 자신이 누구라는 것을 증명할 수 있다. 

Putting all together (모든 요소 조합하기)

결과물은 Base64 로 인코딩 된 URL string 으로 "." 으로 구분되며, HTML 이나 HTTP 환경에서 쉽게 전달 될 수 있다. SAML과 같은 XML 기반 표준들과 비교했을 때 훨씬 더 압축되어 있는 형태다. 

다음은 아래는 위에서 정의했던 인코딩된 헤더와 페이로드 그리고 시크릿으로 서명된 것이 조합된 JWT 이다. 

 

위의 값을 jwt.io Debugger  를 사용해서 디코드하면, 아래 캡쳐화면과 같은 것을 확인할 수 있다. 이 화면을 통해 구체적으로 JWT가 어떻게 구성되는지 확인 할 수 있다. 

JSON Web Tokens 은 어떻게 동작할까?

인증 과정에서 사용자가 그들의 크레덴셜을 이용해서 로그인 하면 JSON Web Token 을 반환 받을 것이다. 토큰이 크레덴셜이므로, 반드시 보안 문제들이 일어나 않도록 주의해야 한다. 일반적으로, 필요이상으로 토큰들을 오래 유지해서는 안된다. 

또한 민감한 정보는 브라우저 스토리지에 저장해서는 안된다.(https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage)

보호된 루트나 리소스를 사용자가 접근하려고 할 때마다, 사용자 에이전트는 JWT 를 보내야 하는데 보통 Authorization 헤더에 Bearer 스키마를 사용한다. 헤더의 컨텐트는 다음과 같이 표시될 것이다. 

Authorization: Bearer <token>

이런 방식은특정 경우에 무상태 인가 메커니즘이 될 수 있다. 서버의 보호되는 경로들의 접근에 대해서는 Authorization 헤더의 JWT 를 체크할 것이다. JWT 가 있을 경우에 보호되는 리소스들에 접근이 허용될 것이다. JWT 가 필요한 데이터들을 포함하고 있을 경우에는 데이터베이스에 쿼리하는 케이스가 줄어 들 수 도 있으나 항상 그런것은 아니다. 

토큰이 Authorization 헤더에 포함되어 전송되면, 쿠키를 사용하는 것이 아니기 때문에 Cross-Origin Resource Sharing (CORS) 를 발생시키지는 않을 것이다. 

아래 그림은 JWT 를 어떻게 획득되어서 API 나 리소스들 접근에 사용되는지를 보여 준다. 

  1. 애플리케이션 또는 클라이언트가 인가서버에 인가를 요청. 인가는 다른 인가 플로들 중 하나를 통해 수행되는데 예를들어 일반적으로 OpenID Connect 스펙을 따르는 웹 애플리케이션은 authorization code flow 를 활용해서 "/oauth/authorize" 엔드포인트를 호출할 것이다. 
  2. 인가가 승인되면, 인가 서버는 애플리케이션에서 액세스 토큰을 반환한다. 
  3. 애플리케이션은 API 와 같은 보호되는 리소스에 접근하기 위해서 액세스 토큰을 사용한다. 

서명된 토큰내에 포함되어 있는 모든 정보 변경될 수는 없어도 사용자들이나 다른 참여자들에게 노출되므로 토큰내에 시크릿 정보를 포함시켜서는 안된다. 

왜 JSON Web Tokens 을 사용해야 할까 ?

Simple Web Tokens (SWT)Security Assertion Markup Language Tokens (SAML) 과 비교하여 JSON Web Tokens (JWT) 의 장점들은 다음과 같다. 

JSON 은 XML 보다 설명정보가 더 적기 때문에 더 작은 작은 사이즈로 인코딩 될 수 있 때문에 SAML 보다 더 축약될 수 있으며, 이런 방식은 HTML 과 HTTP 환경에서 전송하는데 좋은 방법이다. 

보안과 관련하여, SWT는 HMAC 알고리즘을 사용해서 공유되는 시크릿을 가지고 대칭으로만 서명될 수 있다. JWT 와 SAML 토큰들은 서명에 X.509 증명서 형태로 public/private 키 쌍을 사용할 수 있다. obscure security holes(?, 보안 취약점들을 숨기는 기술로 보인다) 도입 없이 XML Digital Signature 를 이용해서 XML을 서명하는 것은 JSON을 서명하는 일읜 단순함과 비교했을 때 매우 어려운 일이다. 
 

JSON 파서들은 대부분의 프로그램 언어들에 흔히 있으며, 객체에 직접 매핑될 수 있다. 반대로 XML은 문서-객체를 자연스럽게 매핑하는 것이 없는데 이 방식이 SAML 보다 JWT와 작업하는 것을 더 쉽게 만들어 준다.

사용성과 관련해서는 JWT는 인터넷 환경에서 사용된다. 이 것은 클라이언트 측의 여러 플랫폼 상에서 (특히 모바일) JSON Web token을 처리하기 쉽다는 것을 강조한다. 

인코딩된 JWT 길이와   인코딩 된  SAML 길이 비교