ToolActToolAct

JWT 분석 도구

JSON Web Token을 디코딩하고 검증하며, Header, Payload와 Signature를 확인합니다

JWT Token

JWT 예시

JWT란?

JWT (JSON Web Token)는 각 방 사이에서 정보를 안전하게 전송하기 위한 개방형 표준 (RFC 7519)입니다. JWT는 세 부분으로 구성되며, 점으로 구분됩니다: Header(헤더)는 토큰 유형과 서명 알고리즘을 포함하고, Payload(페이로드)는 클레임 데이터를 포함하며, Signature(서명)는 토큰 무결성을 검증하는 데 사용됩니다. JWT는 인증과 정보 교환 시나리오에서 자주 사용됩니다.

사용 방법

사용 방법

  1. 입력란에 JWT를 붙여넣으면 도구가 자동으로 파싱하여 헤더와 페이로드 내용을 표시합니다
  2. 색상 태그를 클릭하여 해당하는 Base64 인코딩 부분을 복사하세요
  3. 서명 검증 영역에 시크릿을 입력하여 서명이 올바른지 확인하세요 (HS256/HS384/HS512 알고리즘 지원)
  4. 주요 정보 영역에 클레임의 디코딩 값이 표시되며, 만료 상태는 색상으로 구분됩니다

보안 팁

  • 이 도구는 브라우저에서 로컬로 실행되며, 토큰은 어떤 서버로도 전송되지 않습니다
  • JWT는 데이터를 인코딩하고 서명할 뿐이며 암호화되지 않습니다. 누구나 디코딩하여 내용을 확인할 수 있습니다
  • JWT에 민감한 정보를 저장하지 마세요 (비밀번호, 신용카드 번호 등)
  • 프로덕션 환경에서는 항상 HTTPS를 사용하여 JWT를 전송하세요

활용 사례

인증 디버깅 중 토큰 내용 확인하기세 부분으로 된 JWT(Header.Payload.Signature)를 붙여넣으면 서명과 별도로 Base64URL 디코딩된 헤더와 페이로드를 각각 확인할 수 있습니다. iss, aud, sub, iat, nbf, exp 같은 표준 클레임이 Unix 초와 사람이 읽을 수 있는 날짜 형태로 표시되어 로그인 및 세션 문제를 쉽게 파악할 수 있습니다. 토큰은 브라우저 탭을 벗어나지 않습니다.
로컬에서 HMAC 서명 확인하기HS256, HS384, HS512 토큰의 경우 공유 시크릿을 입력하면 header_b64 + '.' + payload_b64에 대해 HMAC-SHA256/384/512를 재계산하여 서명 세그먼트와 비교합니다. 환경 간 비교, 시크릿 순환 진단, 전송 중 변조 여부 확인에 유용합니다. 붙여넣은 시크릿은 로컬 HMAC 계산에만 사용되며 서버로 전송되지 않습니다.
로그 공유 전에 만료 및 클레임 상세 확인하기도구가 만료된 토큰(exp < 현재)을 강조 표시하고 nbf/iat 경계를 표시하여 '서명은 올바르지만 아직 유효하지 않은' 토큰도 표시합니다. 원본 부분 또는 포맷된 JSON을 복사할 수 있습니다. 디코딩과 HMAC 검증이 브라우저에서 이루어지므로 민감한 베어러 토큰을 외부 디코더 서비스에 전송하지 않고 확인할 수 있습니다.
공개 키 서명 토큰을 로컬 검증 없이 확인하기RS256, PS256 또는 ES256으로 서명된 토큰을 붙여넣으면 디코딩된 헤더와 페이로드를 읽을 수 있습니다. 본 페이지는 HMAC(HS256/HS384/HS512) 서명만 로컬에서 검증하므로 RSA / RSA-PSS / ECDSA 서명 검증은 해당 공개 키를 보유한 서버(일반적으로 발급자의 JWKS 엔드포인트에서 로드)에서 수행해야 합니다. OAuth 콜백을 분석할 때 로컬 탭은 토큰의 클레임 내용만 확인하는 용도로 유용합니다.
알고리즘 혼동 및 누락된 exp 클레임 포착하기디코딩된 보기에서 header.alg와 표준 클레임이 함께 표시되어 토큰은 HS256인데 서버는 RS256을 기대하는 경우(고전적인 알고리즘 대체 공격), alg가 'none'인 경우, 또는 exp/nbf/iat가 없는 경우를 바로 알 수 있습니다. 인증 라이브러리가 검증을 암묵적으로 다운그레이드하기 전에 브라우저에서 해당 불일치를 잡아내세요.

기술 원리

JWT(JSON Web Token, RFC 7519)는 영어 마침표 '.'로 연결된 세 부분 — Header.Payload.Signature — 으로 구성됩니다.

Header: 토큰 유형과 서명 알고리즘을 설명합니다(예: {"alg":"HS256","typ":"JWT"}). alg가 Signature 계산 방식을 결정하며, 주요 알고리즘은 HS256(HMAC-SHA256), RS256(RSA-SHA256), ES256(ECDSA-SHA256), none(서명 없음 - 프로덕션에서 금지)입니다.

Payload: 클레임이라고도 하며, JSON 필드의 집합입니다. RFC 7519는 7가지 표준 등록 클레임을 정의합니다: iss(발급자), sub(주제, 보통 사용자 ID), aud(대상), exp(만료), nbf(이전 아님), iat(발급 시각), jti(고유 ID). 개발자는 여기에 비공개 필드를 자유롭게 추가할 수 있습니다(예: userId, role, tenant).

Signature: Header와 Payload를 Base64URL로 인코딩하고 점으로 연결한 뒤, alg가 지정한 알고리즘으로 키를 사용하여 서명합니다. HS256은 HMAC-SHA256(secret, header_b64 + '.' + payload_b64)를 사용하고, RS256은 RSA 개인키를 사용합니다. 수신자는 같은 방식으로 서명을 재계산하고 일치 여부를 확인합니다.

Base64URL과 표준 Base64의 차이: '+'는 '-', '/'는 '_', 끝의 '=' 패딩은 제거되어 URL 경로와 쿼리 문자열에 퍼센트 인코딩 없이 바로 사용할 수 있습니다. Base64URL은 단순한 인코딩일 뿐 암호화나 보안을 제공하지 않으며, 누구나 디코딩하여 페이로드를 읽을 수 있습니다.

보안 경계: JWT는 '변조되지 않았음'만 보장할 뿐, '내용이 민감하지 않음'은 보장하지 않습니다. 흔한 실수는 사용자 전화번호, 주민등록번호, 비밀번호 해시를 페이로드에 넣는 것이며, 이는 누구나 볼 수 있습니다.
  • 세 부분 구조: Header.Payload.Signature, 각각 Base64URL 인코딩됨. 서명은 HMAC(secret, header_b64 + '.' + payload_b64) 또는 RSA(privateKey, 동일 입력)입니다.
  • Base64URL은 '+'를 '-', '/'를 '_', 끝의 '=' 패딩을 제거하여 인코딩 결과를 URL에 바로 사용할 수 있습니다(퍼센트 인코딩 불필요).
  • 이 도구는 로컬에서 HMAC 계열 서명(HS256/HS384/HS512)만 검증합니다. RS256, ES256 같은 비대칭 알고리즘은 발급자의 JWKS 엔드포인트가 제공하는 공개 키가 필요하므로 서명 검증은 공개 키를 가진 서버에서 수행해야 합니다——페이지에서 헤더와 페이로드를 디코딩할 수는 있지만 검증할 수는 없습니다.
  • 표준 클레임: iss(발급자), sub(주제), aud(대상), exp(만료, 초 단위 Unix 타임스탬프), nbf(이전 아님), iat(발급 시각), jti(JWT ID, 재사용 방지).
  • alg=none 공격: alg 필드를 엄격히 검증하고 none 알고리즘을 거부해야 합니다. 그렇지 않으면 공격자가 임의 토큰을 위조할 수 있습니다. 알고리즘 대체 공격(HS256 토큰을 공개키를 시크릿으로 사용하여 검증하는 것)도 방지해야 합니다.
  • JWT는 암호화되지 않습니다: 페이로드는 평문 Base64URL 인코딩이며, 암호화되지 않습니다. 기밀 콘텐츠에는 JWE(JSON Web Encryption)를 사용해야 하지만, 실무에서는 민감한 데이터를 백엔드에 두고 sub 필드로 참조하는 패턴이 일반적입니다.

예시

표준 HS256 토큰

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNzA1MzEyODAwLCJleHAiOjE3MDUzMTY0MDB9.znHapMygT8K8YZN4K8zM1sV3bKlQ5pY3xE2gR4wN1vM

헤더:  {"alg":"HS256","typ":"JWT"}
페이로드: {"sub":"1234567890","name":"Jane Doe","iat":1705312800,"exp":1705316400}
RFC: RFC 7519 section 3에서 Registered Claim Names (sub, iat, exp)를 정의합니다

만료된 토큰

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMyIsImV4cCI6MTYwMDAwMDAwMH0.OxQ0fUKW0z4mK0xJ4vF0uF7eZB9wK3yF8pL2nQ6tX1k

헤더:  {"alg":"HS256","typ":"JWT"}
페이로드: {"sub":"user-123","exp":1600000000}
상태:  만료됨 (exp < now)
참고: exp 클레임은 NumericDate(Unix epoch 기준 초 단위)를 사용합니다 (RFC 7519 section 2)

사용자 정의 클레임이 포함된 사용자 정보 토큰

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTQ1NiIsIm5hbWUiOiJBbGljZSIsInJvbGUiOiJhZG1pbiIsInRlbmFudCI6ImFjbWUiLCJpYXQiOjE3MDUzMTI4MDAsImV4cCI6MTcwNTMxNjQwMCwiYXVkIjoiYXBpLmV4YW1wbGUuY29tIn0.7Hk2L9oP3qR1mN4vK8xJ2wE5yT6sB0fA9cZ1dG3hI4U

헤더:  {"alg":"HS256","typ":"JWT"}
페이로드: {"sub":"user-456","name":"Alice","role":"admin","tenant":"acme","iat":1705312800,"exp":1705316400,"aud":"api.example.com"}
참고: role, tenant은 사용자 정의 클레임으로 RFC 7519에 정의되어 있지 않습니다

JWT 구현 시 보안 체크리스트

1. 페이로드에 시크릿을 저장하지 마세요 - JWT는 암호화가 아니라 인코딩만 됩니다
2. HS256에는 충분히 강력한 시크릿을 사용하세요 (256비트 / 32자 이상의 랜덤 문자열)
3. 멀티 서비스 환경에서는 공개 키 검증을 위해 RS256/ES256을 우선 사용하세요
4. alg 헤더를 검증하세요 - 'none'이나 예상치 못한 알고리즘은 거부해야 합니다
5. 토큰을 신뢰하기 전에 exp, nbf, iat 타임스탬프를 확인하세요
6. 앱 간 토큰 재사용을 방지하기 위해 aud가 자신의 서비스와 일치하는지 검증하세요
7. localStorage가 아닌 HttpOnly 쿠키에 저장하세요 (XSS 방지)

RFC: RFC 8725 (JWT Best Practices)에서 이러한 보안 고려사항을 다룹니다

자주 묻는 질문

JWT의 세 부분은 무엇인가요?

점으로 구분된 헤더, 페이로드, 시그니처입니다. 헤더는 서명 알고리즘과 토큰 타입을 선언하고, 페이로드는 sub, iss, aud, iat, exp 등의 클레임과 커스텀 데이터를 담으며, 시그니처는 토큰이 변조되지 않았음을 검증자가 확인할 수 있게 해 줍니다. 헤더와 페이로드는 Base64URL로 인코딩된 JSON이며, 서명되어 있을 뿐 암호화되어 있지는 않습니다.

JWT는 암호화되어 있나요?

아니요. 일반적인 JWS 형식의 JWT는 서명만 되어 있고 암호화되어 있지 않습니다. 가로챈 사람은 누구나 헤더와 페이로드를 Base64URL로 디코딩해 사용자 ID, 이메일, 권한 등 모든 클레임을 읽을 수 있습니다. JWT 내용은 공개 정보로 취급하고, 페이로드에 비밀번호나 시크릿을 절대 넣지 마세요. 암호화된 JWT인 JWE도 있지만 훨씬 덜 일반적입니다.

각 표준 클레임은 어떤 의미인가요?

iss는 발급자, sub는 주체(보통 사용자 ID), aud는 청중(의도된 수신자), exp는 만료(Unix 초), nbf는 not before, iat는 발급 시각, jti는 폐기용 고유 토큰 ID입니다. 이들은 RFC 7519에 정의되어 있으며, 커스텀 클레임은 자유롭게 추가할 수 있습니다. 충돌을 피하려면 벤더 고유 클레임에 접두사를 붙이세요.

JWT를 어떻게 검증하나요?

헤더의 alg를 읽고, 그에 맞는 키(HS256은 공유 시크릿, RS256/ES256은 발급자의 JWKS 엔드포인트에서 가져온 공개키)를 사용해 인코딩된 header.payload에 대한 시그니처를 다시 계산해 비교하세요. 그런 다음 exp, nbf, iss, aud를 확인합니다. alg가 'none'이거나 서버가 기대하는 값과 다르면 토큰을 거부해야 합니다. 이 도구는 로컬에서 HS256/HS384/HS512(공유 시크릿) 서명만 검증합니다. RS256/ES256 검증은 공개 키를 가진 서버에서 수행해야 합니다.

검증이 브라우저에서 이뤄지나요?

네. 페이지는 JWT를 로컬에서 파싱하고 HS256/HS384/HS512 서명은 브라우저 내에서 실행되는 JavaScript HMAC으로 검증합니다. 토큰은 저희 서버에 도달하지 않지만, JWT 자체가 URL과 HTTP 헤더로 전달되도록 설계되었음을 잊지 마세요——복사한 JWT는 어떤 식으로든 로그에 남을 수 있다고 전제하세요.

alg=none이 왜 위험한가요?

RFC 7519는 서명 없는 토큰을 위해 alg=none을 허용합니다. 취약한 검증기는 시그니처가 없는데도 이를 받아들여, 공격자가 임의의 페이로드를 위조할 수 있게 만듭니다. 최신 라이브러리는 기본적으로 alg=none을 거부합니다. 검증기를 직접 작성한다면 헤더를 신뢰하지 말고 기대하는 알고리즘을 하드코딩하세요.

JWT는 얼마나 커질 수 있나요?

프로토콜상 제한은 없지만, JWT는 보통 HTTP 헤더(Authorization: Bearer ...)에 실리고 많은 서버는 헤더 크기를 8KB 정도로 제한합니다. JWT에 클레임을 잔뜩 넣으면 매 요청이 무거워집니다. 세션 상태가 많이 필요하다면 서버 사이드 세션을 쓰고, JWT에는 작은 참조 토큰만 넣으세요.