sungyup's.

Web_Miscellaneous / 기초 개념 / 1.7 JWT

1.7JWT

인증에 자주 쓰이는 전자서명된 토큰, JWT의 개념과 구조

TL;DR

추억의 쪽지 시험

JWT(JSON Web Token) 개요

JWT는 JSON 데이터를 Base64url 인코딩 + 전자서명해서 만든 서명된 토큰으로, Header, Payload, Signature 세 부분으로 이루어진다.

여기서 중요한 부분은 JWT는 암호화가 아니라 서명 + 인코딩이라는 점이다. JWT의 Payload는 Base64 인코딩일 뿐이라, jwt.io와 같은 사이트에서 내용을 쉽게 디코딩할 수 있다. JWT가 인증 등에 사용될 수 있는 것은, Payload 내용이 아니라 Signature를 만드는데 쓰이는 비밀 키 덕분이다.

즉, JWT는 내용을 암호화해주진 않지만 서명을 통해 변조를 막아준다.

jwt.io
이미지 출처 : #
jwt.io에 토큰을 붙여넣으면 Payload를 확인할 수 있기에 보안성이 없는것으로 생각할 수 있다. 하지만, 실제 JWT의 보안은 Signature 부분에 있다.

JWT 구조 세부

JWT 문자열은 보통 점(.)으로 세 조각으로 나뉜다.

text
aaaaaa.bbbbbb.cccccc

1. Header(헤더)

헤더는 이 토큰이 어떤 알고리즘으로 서명되었는지 같은 메타 정보를 담는다.

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

2. Payload(페이로드)

실제 담기는 데이터다. 예를 들어 ID, 토큰 만기일자 등이 포함된다. 이러한 Payload의 각 항목들을 claim(클레임)이라고 부른다.

javascript
{"userId": "37", "name": "sungyup", "exp": 173000000}

일반적으로 Payload에 들어가는 claim에는 sub(subject, 보통 유저 식별자), iat(issued at, 발급 시각), exp(expiration, 만료 시각)이 들어간다.

유저 식별자와 만료 시각이 있으면 서버는 굳이 별도의 세션 저장소를 두고 확인할 필요 없이 이 JWT만 봐도 인증 상태를 확인할 수 있게 된다. 이렇게 JWT만으로 인증 상태를 확인하는 방식을 stateless 인증이라고 부른다.

3. Signature(서명)

위의 Header와 Payload를 합쳐서 비밀키/개인키로 서명한 결과다.

보다 구체적으로는, Header, Payload를 각각 JSON → Base64url 인코딩한다. 이후, 이 인코딩된 문자열을 .으로 이어붙인 문자열에 대해 비밀키 또는 개인키를 이용해 서명한다. JWT 문자열의 점으로 나뉜 각 파트는 순서대로 Header, Payload, Signature다.

이 서명은 검증하는 곳에서 공개키로 검증하거나(RS256 같은 비대칭키 방식), 서버가 발급 시 비밀키로 서명한 JWT를 같은 비밀키로 계산해 비교한다(HS256 같은 대칭키 방식).

디지털 서명은 두 가지를 보장한다:

  1. 무결성(Integrity) : 토큰 내용(Header + Payload)이 중간에 한 글자도 바뀌지 않았음
  2. 진위(Authenticity) : 해당 토큰은 비밀키/개인키를 가지고 있는 주체가 만든 것임

이는 서명이 Header와 Payload를 합친 값을 계산한 결과이기 때문이다. 토큰 내용을 보거나 수정할 수는 있지만, 수정할 경우 Signature가 더 이상 일치하지 않게 된다. 검증하는 쪽에서는 서명을 다시 계산해 비교함으로, 이 토큰이 비밀키로 발급된 "진짜 토큰"인지, 중간에 변조된 것인지를 판별할 수 있다.

따라서 JWT 안에는 주민번호, 카드번호처럼 민감한 정보를 넣으면 안된다. JWT 자체는 암호화를 제공하지 않고 JWT가 도청당할 수 있기 때문인데, 전송 구간에서의 도청 방지는 JWT의 담당이 아니라 HTTPS(TLS)의 영역이다.

내용 자체도 암호화된 JWT를 쓰고 싶다면, JWE(JSON Web Encryption)이라는 방법도 있다. 하지만 실무에서 대부분은 민감한 정보는 서버 DB에 두고, JWT로는 인증을 진행해 이 인증을 통과하면 제공하는 방식을 사용한다.
sungyup's