JWT(JSON Web Token)의 구조

양성준·2025년 7월 6일

스프링

목록 보기
46/49

Header (헤더)

  • JSON 객체로, 주로 두 가지 정보를 포함한다.
    • typ: 토큰의 타입(일반적으로 "JWT")
    • alg: 서명에 사용된 해싱 알고리즘(예: HS256, RS256 등)
{
  "alg": "HS256",
  "typ": "JWT"
}
  • 토큰의 타입과 서명에 사용할 알고리즘 정보를 명시하며, 이 정보는 토큰의 검증 및 해석에 사용된다.

Payload (페이로드)

  • 토큰에 담길 실제 데이터(클레임, Claim)들이 들어있는 JSON 객체
  • 클레임의 종류
    • 등록된 클레임: JWT 표준에 정의된 예약된 클레임. (예: iss(발급자), exp(만료 시간), sub(주제), aud(대상자), iat(발급 시각) 등)
    • 공개 클레임: 사용자 정의 클레임으로, 충돌 방지를 위해 URI 형식의 이름을 권장
    • 비공개 클레임: 토큰을 사용하는 당사자 간에 정의한 임의의 정보(예: userId, role 등)
  • 인증된 사용자 정보, 권한, 토큰의 유효기간 등 실제 서비스에서 필요한 정보를 담아 전달한다. 단, 페이로드는 Base64URL로 인코딩(암호화X)만 되어 있으므로, 민감한 정보는 넣지 않는 것이 원칙
    • 패스워드 등 비밀 정보를 넣으면 절대 안 됨!
    • 페이로드는 언제든 조작이 가능하다.
{
  "sub": "1234567890",
  "name": "John Doe",
  "role": user,
  "iat": 1516239022
}
  • 여기서 role을 admin으로 변경하고 Base64 인코딩해 페이로드에 넣어주면 해당 토큰의 role을 admin으로 인식함

=> 위조를 방지하기 위해 signature (서명)이 필요!

Signature (서명)

  • 헤더와 페이로드를 각각 Base64Url로 인코딩한 후, 헤더에서 명시한 알고리즘과 서버의 비밀키(혹은 개인키)로 서명한 값
signature = HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)
  • 토큰의 무결성과 위변조 방지를 보장한다. 서명이 올바르지 않으면 토큰이 변조된 것으로 간주하여 인증에 실패
  • 서버만이 비밀키를 알고 있으므로, 서명을 통해 토큰의 신뢰성을 검증할 수 있다.

검증 과정
1. 도착한 AccessToken의 헤더와 페이로드를 base64url로 인코딩한 뒤, 동일한 비밀키로 서명
2. AccessToken의 signature와 동일한지 확인
3. 동일하다면, 서버에서 발급한 토큰이 맞으므로 인증 / 다르다면 위조된 토큰이므로 거부

String base64UrlHeaderPayload = base64Url(header) + "." + base64Url(payload);

String expectedSignature = HMACSHA256(base64UrlHeaderPayload, secretKey);

if (!expectedSignature.equals(clientSignature)) {
    throw new SecurityException("Invalid JWT: signature mismatch");
}

=> 이 과정을 통해 Payload가 바뀌었거나, 비밀키를 모르는 공격자가 만든 토큰인지를 판별할 수 있다.

profile
백엔드 개발자를 꿈꿉니다.

0개의 댓글