JWT(JSON Web Token)란 무엇인가
JSON Web Token(이하 JWT)은 당사자 간에 정보를 안전하게 JSON 객체 형태로 전송하기 위해 정의된 공개 표준(RFC 7519)이다. 웹 애플리케이션에서 클라이언트와 서버가 로그인 인증 정보나 권한 데이터를 주고받을 때 표준 규격으로 널리 사용되며, 특히 JSON CSV 변환 원리와 중첩 데이터 평탄화 매핑 완벽 가이드에서 다루는 것과 같은 복잡한 JSON 데이터 구조를 효율적으로 다루는 원리가 기반이 된다.
JWT는 위조 방지 직인이 찍힌 놀이공원 자유이용권 팔찌에 비유할 수 있다. 팔찌에는 사용자의 이름과 이용 가능 일자가 적혀 있고 관리자의 직인이 날인되어 있다. 놀이공원 직원이나 다른 이용자 누구나 팔찌에 적힌 글씨를 눈으로 읽을 수 있지만, 직인이 훼손되었거나 위조된 팔찌로는 놀이기구에 탑승할 수 없다. JWT 역시 토큰 내부 데이터를 누구나 열람할 수 있지만, 위변조 방지 서명이 올바르지 않으면 서버가 요청을 거부한다.
JWT의 3단 내부 구조와 동작 원리
JWT는 마침표(.)를 구분자로 사용하는 세 부분의 문자열이 결합된 형태를 띤다. 전체 토큰 구조는 Header.Payload.Signature로 표현된다.
| 구성 요소 | 주요 역할 | 데이터 형식 |
|---|---|---|
| Header | 토큰 유형과 서명 생성에 쓰인 알고리즘 정의 | Base64Url로 인코딩된 JSON |
| Payload | 토큰에 담길 실제 정보(사용자 식별자, 만료일 등) | Base64Url로 인코딩된 JSON |
| Signature | 데이터 위변조 여부를 검증하기 위한 서명값 | 비밀키 또는 개인키로 생성된 해시값 |
1. 헤더(Header)
헤더는 토큰의 유형(typ)과 시그니처를 해싱할 알고리즘(alg) 정보를 담는다. JSON 형태로 작성된 뒤 Base64Url 규격으로 인코딩된다.
{
"alg": "HS256",
"typ": "JWT"
}
여기서 alg 속성의 HS256은 SHA-256 해시 함수를 사용하는 HMAC 알고리즘을 의미한다. 비대칭키 방식을 사용할 때는 RS256 등이 지정된다.
2. 페이로드(Payload)
페이로드는 토큰으로 전달하려는 실제 데이터 조각인 클레임(Claim)을 포함한다. 클레임은 키-값 쌍으로 구성되며 크게 세 가지 종류로 나뉜다.
- 등록된 클레임(Registered Claims): 토큰 발급자(iss), 토큰 대상자(sub), 만료 시간(exp), 발급 시간(iat)처럼 표준 사양에 미리 정의된 속성이다.
- 공개 클레임(Public Claims): 충돌을 방지하기 위해 URI 형태로 정의하거나 IANA JSON Web Token 레지스트리에 등록하여 사용하는 속성이다.
- 비공개 클레임(Private Claims): 서버와 클라이언트가 협의하여 자유롭게 정의하는 커스텀 속성이다.
{
"sub": "user_98765",
"name": "홍길동",
"role": "admin",
"iat": 1774450000,
"exp": 1774453600
}
3. 시그니처(Signature)
시그니처는 헤더와 페이로드가 네트워크 전송 과정에서 위변조되지 않았음을 증명하는 서명값이다.
인코딩한 헤더와 페이로드를 마침표(.)로 연결한 뒤, 서버만 아는 비밀키(Secret Key)를 더해 헤더에 지정된 알고리즘으로 해시를 생성한다.
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret_key
)
클라이언트가 API를 호출하며 토큰을 전달하면, 서버는 수신한 헤더와 페이로드를 바탕으로 서명값을 다시 계산한다. 이 값이 토큰에 포함된 시그니처와 정확히 일치해야 데이터가 변조되지 않은 것으로 판단하고 요청을 처리한다.
Base64Url 인코딩의 이해
- +, /, = 문자 포함
- URL 쿼리 및 HTTP 헤더에서 특수 제어 문자로 해석되어 데이터 깨짐 발생 가능
- +를 -, /를 _로 치환
- 패딩 문자(=) 제거로 URL 및 HTTP 헤더에서 별도 이스케이프 없이 안전하게 전송 가능
URL 및 HTTP 전송 환경에 최적화된 인코딩 규격
JWT의 헤더와 페이로드는 일반 Base64가 아닌 Base64Url 방식으로 인코딩된다.
일반 Base64 인코딩 결과물에는 +, /, = 문자가 포함된다. 이러한 문자는 URL 쿼리 파라미터나 HTTP 헤더에서 특수 제어 문자로 해석되어 데이터가 깨지거나 누락되는 문제를 유발한다.
Base64Url은 +를 -로, /를 _로 치환하고 끝부분의 패딩 문자(=)를 제거한다. 그 결과 URL이나 HTTP 헤더 어디에나 별도의 이스케이프 처리 없이 안전하게 전송할 수 있다.
JWT를 둘러싼 오해와 진실
JWT를 다룰 때 흔히 생기는 착각을 바로잡는다.
오해 1: JWT는 페이로드 데이터를 암호화하여 숨겨준다? 실제로는 그렇지 않다. JWT(정확히는 JWS)는 서명만 제공하며 페이로드는 단순 Base64Url 인코딩 상태다. 암호화 키 없이도 누구나 원본 JSON 문자열로 디코딩할 수 있다. 따라서 비밀번호, 주민등록번호, 계좌번호 같은 민감 정보는 페이로드에 절대 담지 않아야 한다.
오해 2: 시그니처가 존재하므로 토큰을 도난당해도 안전하다? 사실은 토큰 자체가 탈취되면 심각한 보안 사고로 이어진다. 서명은 데이터의 '위조와 변조'를 검증하는 수단이지, 토큰 자체의 '도난'을 막는 장치가 아니다. 토큰이 유효한 동안에는 공격자도 정상 사용자로 위장해 시스템에 접근할 수 있다. 따라서 토큰 유효기간을 짧게 유지하고 HTTPS 암호화 통신을 필수로 적용해야 한다.
오해 3: JWT는 서버 자원을 전혀 소모하지 않는 완벽한 무상태 인증이다? 실제로는 뚜렷한 장단점이 공존한다. 서버가 세션 저장소를 조회하지 않아 수평 확장에 유리하지만, 이미 발급한 토큰을 중간에 강제로 무효화하기 어렵다. 사용자가 로그아웃하거나 권한이 박탈됐을 때 토큰을 즉시 차단하려면 별도의 토큰 블랙리스트 저장소를 운영해야 하며, 이 경우 순수한 무상태성의 이점이 일부 줄어든다.
전통적인 세션-쿠키 인증과의 차이점
JWT와 세션 기반 인증은 사용자의 인증 상태를 유지하고 검증하는 방식에서 뚜렷한 차이를 보인다.
| 비교 항목 | 세션 기반 인증 (Session) | JWT 기반 인증 (Token) |
|---|---|---|
| 상태 저장 위치 | 서버 메모리 또는 세션 DB | 클라이언트 (토큰 자체에 데이터 내장) |
| 서버 확장성 | 다중 서버 환경에서 세션 동기화 필요 | 무상태 구조로 다중 서버 확장에 유리 |
| 데이터 크기 | 짧은 세션 식별자만 전송 | 사용자 정보와 만료일이 포함되어 큼 |
| 즉각적인 만료 제어 | 서버에서 세션을 삭제하여 즉시 만료 가능 | 만료 시점 전까지 개별 토큰 무효화가 까다로움 |
| 주요 보안 위협 | 세션 하이재킹 및 CSRF 방어 필요 | XSS를 통한 토큰 탈취 방어 필요 |
JWT 토큰 디버깅과 안전한 파싱 방법
개발 과정에서 인증 오류를 추적하거나 토큰의 만료 일시를 파악하려면 JWT를 파싱하여 내부 구조를 검토해야 한다.
일반적으로 웹상에 공개된 온라인 디버거를 많이 쓴다. 하지만 입력한 토큰을 원격 서버로 전송해 파싱하는 도구는 실제 서비스의 토큰이나 내부 시스템 정보가 외부 서버 로그에 노출될 보안 리스크가 있다.
보안에 민감한 토큰 데이터를 점검할 때는 네트워크 전송 없이 브라우저 내부에서 100% 로컬 연산으로 처리하는 JWT 디버거 & 토큰 파서를 활용하는 것이 안전하다. 데이터 유출 우려 없이 헤더의 알고리즘, 페이로드의 클레임 목록, 토큰의 만료 시간을 즉시 확인할 수 있다.
토큰을 디버깅할 때는 다음 세 가지 항목을 순차적으로 점검한다.
- 헤더 알고리즘 검증: alg 값이 사전에 합의된 알고리즘(예: HS256, RS256)인지 확인한다. 알고리즘을 none으로 조작해 서명 검증을 우회하는 취약점이 없는지 살핀다.
- 페이로드 클레임 검토: 사용자 식별자(sub)나 권한(role) 정보가 요구사항에 맞는지 확인하고, 외부에 노출되면 안 되는 민감 데이터가 포함되지 않았는지 점검한다.
- 시간 클레임 계산 확인: 만료 시간(exp)과 발급 시간(iat)이 올바른 유닉스 타임스탬프 형식인지 확인하고, 현재 시간과의 차이를 계산해 토큰 수명이 적절한지 검증한다.