«decoder un JWT»는 무슨 뜻인가요?
JWT 디코딩하기 («jwt decode», «decode jwt online»)이란 문자열을 점으로 나눈 뒤 각 세그먼트를 Base64URL로 디코딩해 원래 JSON을 되찾는 것입니다. 키는 필요 없습니다. 헤더와 페이로드는 암호화가 아니라 인코딩되었을 뿐입니다. «jwt payload decoder»나 «decode jwt without verify»라는 검색 의도가 정확히 이것입니다 — 토큰이 무엇을 담는지 보는 것이지, 그것이 진짜라고 주장하려는 것이 아닙니다.
두 동작을 반드시 구분하세요. 읽기 JWT는 아무것도 증명하지 못합니다. 누구든 그럴듯한 페이로드를 넣은 토큰을 만들어 자기 시크릿으로 서명할 수 있습니다. 검증 서명은 내용이 제3자에 의해 바뀌지 않았음을 증명합니다. 서명 검증 없이 «admin: true»를 보여 주는 디코더는 사실이 아니라 이야기를 들려주는 것입니다.
JWT의 세 세그먼트
문자는 점으로 구분된 정확히 세 부분으로 나뉩니다: header.payload.signature. 헤더에는 최소한 alg 그리고 typ, 가끔은 kid 를 넣어 어떤 키를 사용했는지 나타냅니다. 페이로드에는 claims, 즉 IANA가 레지스트리를 관리하는 키-값 쌍입니다. 서명은 앞의 두 세그먼트를 그대로 이어 붙인 전체를 덮습니다 — 공백 하나, 문자 하나가 바뀌어도 비교는 실패합니다.
모든 어려움은 이 세그먼트가 Base64가 아니라 Base64URL이기 때문입니다. 더하기는 하이픈으로, 슬래시는 밑줄로 바뀌고, 패딩 = 은 사라집니다. 그래서 표준 Base64 디코더는 유효한 JWT에서도 실패합니다. 참고 탭의 «Base64URL과 표준 Base64 비교» 표가 바로 이 치환을 보여 줍니다.
서명 검증 방법: HS256, RS256, ES256
예를 들어 HMAC (HS256, HS384, HS512)는 서명과 검증에 같은 시크릿을 씁니다. 도구는 다음을 다시 계산합니다: HMAC(secret, base64url(header) + "." + base64url(payload)) 결과를 수신된 서명과 비교합니다. 가장 흔하면서 가장 위험한 경우입니다. 시크릿을 가진 모든 서비스가 토큰을 발급할 수 있습니다. 32바이트 미만이고 환경마다 재사용되는 시크릿 하나로 전체 체인이 무너집니다.
또한 비대칭 알고리즘은 (RS256, RS384, RS512, ES256, ES384, ES512, PS256)는 검증에 공개키만 있으면 됩니다. 덕분에 서명 시크릿을 일절 공유하지 않고도 제3자가 발급한 토큰을 검증할 수 있습니다. PEM 형식의 키를 붙여넣으세요 -----BEGIN PUBLIC KEY----- (SPKI)입니다. OpenSSL 출력의 원본 결과를 그대로 쓸 수 있습니다. ES256의 서명은 WebCrypto가 기대하는 r||s 원본 형식입니다.
그리고 마지막으로 경계해야 할 것은alg confusion : 서비스가 RS256을 기대하는데 헤더에 HS256을 선언한 토큰을 받아들이면, 공격자가 그 공개키(이제 HMAC 키가 된)로 서명하고 검증을 통과합니다. 기대하는 알고리즘은 서버 쪽에서 고정하고, 토큰 자체에서는 절대 읽지 마세요.
exp, iat, nbf: 함정이 되는 타임스탬프
이 세 claim은 Unix 초이며, 밀리초도 시간대도 없습니다: iat 이 1516239022는 2018-01-17T21:30:22Z를 뜻합니다. 되풀이되는 두 오류가 있습니다. 밀리초 단위 날짜와 비교하는 것(값이 1만 배 큽니다)과 타임스탬프를 UTC가 아닌 로컬 시간으로 해석하는 것입니다. «만료» 탭은 양방향으로 변환하며 ISO 8601, 로컬 날짜, 남은·경과 시간을 보여 줍니다 — «이미 만료된» 토큰을 초 단위로 바로 잡아낼 수 있습니다.
유효 기간을 늘린다고 보안 수준이 올라가지 않습니다. 예를 들어 exp 을 미룬다고 표시되는 값만 바뀌고 서명은 그대로입니다. 다시 발행해야 한다면 시크릿이나 개인키로 토큰에 다시 서명하세요 — 바로 «인코딩» 탭의 역할입니다.
Base64URL: 표준 디코더가 실패하는 이유
Base64URL(RFC 4648 §5)이 사용하는 알파벳은 A-Z a-z 0-9 - _ 이고 패딩을 허용하지 않습니다. 20자의 페이로드는 = 를 제거한 뒤 길이가 4의 배수가 아닌 경우가 흔합니다. 이는 정상이며 손상이 아닙니다. 문자 - 그리고 _ 는 사람의 눈에 모호해, 신고되는 «깨진 토큰»의 절반이 이 때문입니다. 이 디코더는 두 알파벳, 대소문자 혼용, 선택적 패딩, 그리고 접두사 Bearer.
보안: JWT가 하지 못하는 것
JWT는 기밀성도 폐지 기능도 제공하지 않습니다. 페이로드는 누구나 읽을 수 있습니다. 이메일, 내부 역할, 평문으로 보낼 생각이 없는 개인 정보는 절대 넣지 마세요. 게다가 서명된 토큰은 exp 까지 유효하며 로그아웃 후에도 남습니다 — 폐지 목록, jti 방식의 서버 측 추적, 또는 짧은 유효기간을 두는 것 refresh token. 좋은 습관: exp 는 짧게(10~15분), iat 는 통제하고, nbf 는 같은 기준에 맞추고, iat, aud 그리고 iss 는 수신 시 검증하세요.
추천 대상
백엔드·프론트엔드 개발자(OAuth 2.0, OpenID Connect, REST API), 통합 담당자와 DevOps(신원 인프라, JWKS, 키 로테이션), QA와 침투 테스터(claim 재작성, alg confusion, 만료), 시스템 관리자(원인 불명의 401 디버깅), 학생(Base64URL와 WebCrypto를 이해하려는 사람), 그리고 온라인 JWT 디코더 를 필요로 하되 빠르고 완전하며 안전하기를 바라는 모든 사람에게. 보완 도구로는 Base64 인코더/디코더, URL 인코더/디코더 그리고 JSON 포매터.