JWT 분석 도구
JSON Web Token을 디코딩하고 검증하며, Header, Payload와 Signature를 확인합니다
JWT 예시
JWT란?
JWT (JSON Web Token)는 각 방 사이에서 정보를 안전하게 전송하기 위한 개방형 표준 (RFC 7519)입니다. JWT는 세 부분으로 구성되며, 점으로 구분됩니다: Header(헤더)는 토큰 유형과 서명 알고리즘을 포함하고, Payload(페이로드)는 클레임 데이터를 포함하며, Signature(서명)는 토큰 무결성을 검증하는 데 사용됩니다. JWT는 인증과 정보 교환 시나리오에서 자주 사용됩니다.
사용 방법
사용 방법
- 입력란에 JWT를 붙여넣으면 도구가 자동으로 파싱하여 헤더와 페이로드 내용을 표시합니다
- 색상 태그를 클릭하여 해당하는 Base64 인코딩 부분을 복사하세요
- 서명 검증 영역에 시크릿을 입력하여 서명이 올바른지 확인하세요 (HS256/HS384/HS512 알고리즘 지원)
- 주요 정보 영역에 클레임의 디코딩 값이 표시되며, 만료 상태는 색상으로 구분됩니다
보안 팁
- 이 도구는 브라우저에서 로컬로 실행되며, 토큰은 어떤 서버로도 전송되지 않습니다
- JWT는 데이터를 인코딩하고 서명할 뿐이며 암호화되지 않습니다. 누구나 디코딩하여 내용을 확인할 수 있습니다
- JWT에 민감한 정보를 저장하지 마세요 (비밀번호, 신용카드 번호 등)
- 프로덕션 환경에서는 항상 HTTPS를 사용하여 JWT를 전송하세요
활용 사례
기술 원리
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에는 작은 참조 토큰만 넣으세요.