iGotTools

JWT 토큰을 안전하게 디코딩하고 조사하기

JSON 웹 토큰 안에 정확히 무엇이 있는지 보세요: 발행자, 만료, 스코프, 클레임. 로컬에서 디코딩해 신뢰하기 전에 만료되거나 의심스러운 토큰을 찾아냅니다.

개발 도구

JSON 웹 토큰(JWT)은 로그인 후 당신이 누구인지 증명하기 위해 브라우저가 보내는 문자열이며 — 그것을 가진 사람은 누구나 읽을 수 있습니다. 그것은 설계상의 결함이 아니라 설계 그 자체입니다. 진짜 위험은 토큰을 읽는 것이 아니라 어디서 읽느냐입니다. 유효한(활성) 토큰을 무작위 디코더 사이트에 붙여넣으면 당신의 세션을 통제할 수 없는 서버에 넘기게 됩니다. JWT 디코더는 아무것도 업로드하지 않습니다 — header, payload, 클레임을 전적으로 브라우저에서 디코딩하며, 그것을 앞서 알립니다: 입력 아래 보안 노트는 “브라우저에서 로컬로 디코드합니다. 서명은 검증하지 않습니다.“라고 읽힙니다.

TL;DR

JWT는 봉인된 봉투가 아닙니다. 끝에 서명이 붙은 세 개의 Base64URL 부분이며, 처음 두 개는 변장한 평문입니다.

  • JWT는 세 부분header.payload.signature, 각각 점으로 구분됩니다. 처음 두 개는 Base64URL로 인코딩된 JSON입니다.
  • 토큰을 가진 사람은 누구나 읽을 수 있습니다 — header와 payload는 밀리초 안에, 키 없이 디코딩됩니다.
  • 서명은 기밀성이 아니라 무결성을 증명합니다 — 서버가 토큰이 변조되지 않았음을 확인하게 합니다. 내용을 숨기지 않습니다.

로컬에서 디코딩하고, 토큰이 말하는 것을 읽고, payload를 비밀 보관 장소로 취급하지 마세요.

JWT의 구조

모든 JWT는 점으로 연결된 정확히 세 개의 Base64URL 세그먼트를 가집니다:

<header>.<payload>.<signature>

도구 자체의 샘플 토큰(샘플 버튼으로 불러오기)을 가져와 처음 두 세그먼트를 보세요. 노이즈처럼 보이지만, 각각은 단지 Base64URL로 인코딩된 JSON입니다. 디코딩하면 다음처럼 읽힙니다:

  • Header{"alg":"HS256","typ":"JWT","kid":"example-demo"}. 알고리즘, 토큰 타입, 키 id를 선언합니다. 서버에 어떻게 검증할지 알려줄 뿐, 비밀이 아닙니다.
  • Payload{"iss":"example-app","sub":"demo-user","name":"홍길동","scope":"read write","iat":1704067200,"nbf":1704067200,"exp":4102444800}. 이것들이 클레임입니다: 토큰에 대한 진술 — 누가 발행했는지, 누구 것인지, 무엇을 허용하는지, 언제 만료되는지.
  • Signaturedemo-signature. 실제 토큰에서 이것은 서버가 비밀이나 개인 키로 header와 payload에 대해 계산한 암호학적 값입니다. 도구 샘플은 의도적으로 더미값(placeholder)을 넣습니다.

header와 payload가 읽을 수 있는 부분입니다. 서명은 원본 입력으로 되돌릴 수 없는 유일한 부분이며 — 다른 두 개가 전송 중에 변경되지 않았음을 증명하기 위해 존재하지, 비공개로 유지하기 위함이 아닙니다. (인코딩과 관련된 부분은 Base64 인코딩과 암호화를 보세요 — JWT는 “Base64는 비밀이 아니다”의 실례입니다.)

디코딩되는 표준 클레임

payload는 클레임의 묶음입니다 — 관행으로 합의된 키/값 쌍. 거의 항상 만나는 등록된 것들:

  • iss (발행자) — 토큰을 발행한 주체, 보통 URL이나 식별자.
  • sub (제목) — 토큰이 누구에 대한 것인지, 전형적으로 사용자나 계정 id.
  • aud (수신자) — 토큰이 누구를 위한 것인지. 결제 서비스용으로 발행된 토큰은 프로필 서비스가 거부해야 합니다.
  • exp (만료) — 토큰이 유효하지 않게 되는 순간, 유닉스 타임스탬프로. 확인할 가장 중요한 클레임입니다.
  • iat (발급 시각) — 토큰이 생성된 때.
  • nbf (이전엔 유효하지 않음) — 토큰이 유효한 가장 이른 순간. iat과 결합해 약간 미리 토큰을 발행할 수 있게 합니다.

exp가 중요한 이유는 토큰이 소지자 자격증명이기 때문입니다: 유효한 것을 제시한 사람이 접근 권한을 얻습니다. 짧고 만료되는 토큰은 하나가 도난당했을 때 피해 반경을 줄입니다. exp가 먼 미래인 토큰은 수명이 긴 키이고, exp가 아예 없는 토큰은 사실상 영구적입니다. 토큰이 주장하는 것을 신뢰하기 전에 항상 만료를 읽으세요.

단계별: 토큰 디코딩하기

JWT 디코더는 전적으로 브라우저에서 실행됩니다 — 토큰은 당신의 기기를 떠나지 않습니다. 흐름:

  1. 토큰을 붙여넣습니다. 완전한 header.payload.signature 문자열을 JWT 토큰 입력 상자에 넣습니다. 직접 붙여넣는 대신 내장 데모 토큰을 불러오려면 샘플을 누릅니다.
  2. 디코딩합니다. 디코드를 클릭합니다. 오른쪽 패널이 분석 결과로 채워집니다. (그 후 입력을 편집하면 상태 줄이 “입력이 변경되었습니다. 다시 디코드해 결과를 갱신하세요.“가 되어 과거의 분석 결과를 읽는 일이 없습니다.)
  3. 진단 패널을 읽습니다. 상단에 header에서 뽑은 알고리즘, 타입, Key ID와 각 세그먼트의 바이트 크기를 나열합니다. 잘못되거나 빈 서명 토큰은 여기서 드러납니다 — 여기 경고는 “토큰이 만료되었습니다.”, “토큰이 아직 유효하지 않습니다.”, “서명 세그먼트가 비어 있습니다. 디코드는 서명을 검증하지 않습니다.“가 됩니다.
  4. 클레임 타임라인을 확인합니다. 표는 시간 기반 클레임 — exp, iat, nbf — 을 원시 초, ISO UTC 읽기, 그리고 활성·과거·미래상태로 펼칩니다. exp 행이 과거인 토큰은 만료된 것이고, nbf 행이 미래면 아직 유효하지 않음을 뜻합니다.
  5. Header와 Payload 패널을 읽습니다. 각각은 복사 버튼이 있는 정돈된 JSON입니다. 토큰의 완전하고 디코딩된 내용 — 발행자, 제목, 스코프, 전부 — 입니다.
  6. 필요한 것을 복사합니다. 단일 패널은 복사, header·payload·서명을 함께 묶은 텍스트 요약은 전체 복사를 씁니다. 모두 지우려면 초기화를 씁니다.

전부 읽기 작업입니다. 도구는 외부로 요청을 보내지 않고, 발행자에 대해 서명을 검증하지 않으며, 토큰을 저장하지 않습니다 — 페이지를 새로고침하면 사라집니다.

결정적 오해

JWT가 인증에 쓰이기 때문에 사람들은 그 내용이 비밀이라고 가정합니다. 아닙니다. header와 payload는 Base64URL로 인코딩되어 있으며, 그것은 인코딩이지 암호화가 아닙니다 — 키 없이 누구나 한 단계로 되돌릴 수 있습니다. (이것은 Base64를 보안으로 취급하는 것과 같은 함정입니다; Base64 인코딩과 암호화를 보세요.)

하나의 철칙이 있습니다: JWT의 payload에 비밀을 절대 넣지 마세요. 비밀번호도, API 키도, 신용카드 번호도, 어떤 종류의 자격증명도. payload에 있다면 공개된 것으로 간주하세요 — 토큰이 서버를 떠나는 순간, 경로상의 누구나 읽을 수 있기 때문입니다. 서명은 토큰이 변경되지 않았음을 보장합니다; 누가 볼 수 있는지에 대해서는 아무것도 보장하지 않습니다.

토큰을 디코딩했을 때 payload가 깔끔히 읽히면, 그것은 형식이 정직함을 뜻합니다 — 내용이 비공개임을 뜻하지 않습니다. 그에 맞게 설계하세요: 클라이언트가 필요한 것만 payload에 넣고, 진짜 비밀은 서버 측에 두며, 짧은 exp 값이 보호를 맡게 하세요.

관련 확인

디코딩이 첫 질문입니다. 인접한 몇 가지 도구가 나머지 질문에 답해줍니다:

  • Base64 부분을 검증합니다. 각 세그먼트는 Base64URL입니다 — Base64 도구로 왕복을 확인합니다. 이것은 JWT의 내용이 숨겨져 있지 않음을 증명하는 방법이기도 합니다: 세그먼트를 붙여넣고 디코딩하면 JSON이 곧바로 돌아옵니다.
  • 타임스탬프를 확인합니다. exp, iat, nbf는 유닉스 초입니다. 타임스탬프 변환기로 사람이 읽을 수 있는 날짜로 바꿔 토큰이 언제 만료되거나 유효해졌는지 정확히 보세요.
  • 해시로 무결성. JWT의 서명은 변조되지 않았음을 증명합니다. 파일이나 임의 문자열에 같은 작업을 하려면 해시·체크섬 생성기로 해시를 비교합니다 — 일치하는 다이제스트는 “변경 없음”을 뜻하고, 키를 교환하지 않습니다.

자주 묻는 질문

JWT를 디코딩하는 것은 안전한가요?

네 — JWT를 디코딩하는 것은 두 JSON 세그먼트를 Base64URL 디코딩하는 것뿐입니다. 토큰이 소유자에게 평문으로 이미 담고 있는 정보를 보여줄 뿐, 토큰을 약화시키거나 노출하거나 무효화하지 않습니다. 안전하지 않은 것은 어디서 디코딩하느냐입니다: 유효한(활성) 토큰을 알 수 없는 웹사이트에 붙여넣으면 세션이 샐 수 있습니다. JWT 디코더로 브라우저에서 디코딩하면 토큰은 기기를 떠나지 않습니다.

도구가 제 토큰을 읽을 수 있나요?

아니요. JWT 디코더는 전적으로 클라이언트 측에서 실행됩니다. 토큰은 브라우저 메모리에서 분석됩니다; 아무것도 업로드·기록·저장되지 않습니다. 입력 아래 보안 노트가 직접 그것을 진술합니다: “브라우저에서 로컬로 디코드합니다.” 페이지를 새로고침하면 입력이 지워집니다.

여기서 “만료”는 무슨 뜻인가요?

토큰의 exp 클레임 — 만료 타임스탬프 — 가 과거에 있음을 뜻하므로, 검증하는 서버는 그것을 거부해야 합니다. 도구에서 만료된 토큰은 클레임 타임라인에서 exp과거로 표시되고 진단 패널에서 “토큰이 만료되었습니다.” 경고를 일으킵니다. “만료”는 유효성에 관한 것이지 가독성이 아닙니다: 토큰은 여전히 문제없이 디코딩되지만, 신뢰해서는 안 됩니다.

토큰은 어디서 검증되나요?

이 도구에서는 아닙니다. JWT 디코더는 디코딩합니다 — header와 payload를 읽고 클레임 타임라인을 보여줍니다. 발행자 키에 대해 서명을 검증하지 않으므로, 토큰이 진짜인지는 알 수 없고, 토큰이 주장하는 내용만 보여줍니다. 진짜 검증(서명, exp, aud, 발행자 확인)은 토큰을 발행하거나 신뢰하는 서버에서 일어납니다. 그래서 보안 노트가 명시적입니다: “서명은 검증하지 않습니다.”

iGotTools

이 도구로 시작

지금 시작하기