← 가이드 목록

JWT 디코딩으로 exp, iat, payload 확인하는 방법

JWT의 세 부분 구조와 주요 claim의 의미, 인증 문제를 디버깅할 때 무엇부터 확인해야 하는지 정리했습니다.

jwt decode jwt payload jwt exp jwt claims

JWT의 구조

JWT는 점으로 구분된 세 부분으로 이루어집니다. 앞에서부터 header, payload, signature입니다.

header와 payload는 JSON을 URL-safe Base64로 인코딩한 것입니다. 암호화가 아니라 인코딩이므로 토큰을 가진 사람은 누구나 내용을 읽을 수 있습니다. 이것이 JWT를 이해할 때 가장 먼저 알아야 할 사실입니다.

signature는 header와 payload를 비밀 키로 서명한 값입니다. 내용을 숨기는 것이 아니라 내용이 변조되지 않았음을 증명하는 역할입니다. 누군가 payload의 권한 값을 admin으로 고치면 서명이 맞지 않게 되어 서버가 거부합니다.

주요 claim의 의미

payload에 들어가는 값을 claim이라고 합니다. 표준으로 정해진 것들은 아래와 같습니다.

  • exp (expiration time): 만료 시각. Unix 초 단위 정수입니다. 이 시각이 지나면 토큰은 무효입니다.
  • iat (issued at): 발급 시각. 토큰이 언제 만들어졌는지 알 수 있습니다.
  • nbf (not before): 이 시각 이전에는 사용할 수 없다는 의미입니다. 예약된 권한 부여에 쓰입니다.
  • sub (subject): 토큰의 주체. 보통 사용자 ID가 들어갑니다.
  • iss (issuer): 발급자. 여러 인증 서버를 쓰는 환경에서 어디서 발급했는지 구분합니다.
  • aud (audience): 이 토큰을 받아들여야 할 대상 서비스입니다.

인증 문제를 디버깅하는 순서

401이나 403이 발생했을 때 토큰을 디코딩해 보면 원인이 빠르게 드러나는 경우가 많습니다.

첫째로 exp를 확인합니다. Unix 타임스탬프이므로 그대로는 읽기 어렵고 날짜로 변환해야 합니다. 이미 지난 시각이라면 토큰 갱신 로직을 살펴봐야 합니다. 의외로 많은 인증 문제가 여기서 끝납니다.

둘째로 payload의 권한 관련 값을 봅니다. role, scope, permissions 같은 필드에 기대한 값이 들어 있는지 확인합니다. 로그인은 됐는데 특정 기능만 막힌다면 대부분 이 부분입니다.

셋째로 iss와 aud를 확인합니다. 개발 서버에서 발급한 토큰을 운영 서버에 보내는 실수가 생각보다 자주 발생하는데, 이 값을 보면 바로 알 수 있습니다.

payload에 넣으면 안 되는 것

payload는 누구나 읽을 수 있으므로 민감한 정보를 넣으면 그대로 노출됩니다. 비밀번호, 주민등록번호, 카드 번호, 내부 시스템의 상세 구조 같은 것은 절대 넣지 않아야 합니다.

또한 payload가 커질수록 모든 요청의 헤더 크기가 커집니다. 토큰은 매 요청마다 전송되므로 사용자 프로필 전체를 담는 식의 설계는 성능에 불리합니다. 식별자와 최소한의 권한 정보만 넣고 나머지는 필요할 때 조회하는 편이 낫습니다.

디코딩과 검증은 다르다

온라인 도구로 JWT를 디코딩할 수 있다는 것은 토큰이 유효하다는 뜻이 아닙니다. 디코딩은 Base64를 푸는 것일 뿐이고, 검증은 서명이 올바른지 비밀 키로 확인하는 별개의 과정입니다.

검증은 반드시 서버에서 이루어져야 합니다. 클라이언트에서 payload를 읽어 화면 표시를 조정하는 것은 괜찮지만, 그것으로 권한을 판단하면 안 됩니다. 사용자가 payload를 마음대로 고쳐 보낼 수 있기 때문입니다.

특히 header의 alg 값이 none 인 토큰을 받아들이는 서버는 심각한 취약점을 가진 것입니다. 서명 없이 누구나 원하는 권한의 토큰을 만들 수 있게 됩니다. 서버는 허용할 알고리즘을 고정해 두어야 합니다.

이 문서에서 다룬 도구

Copied