JWT의 구조와 원리

Jun_k·2026년 4월 5일

Spring

목록 보기
7/9
post-thumbnail

JWT란 무엇인가?

JWT는 정보를 JSON 객체 형태로 안전하게 전송하기 위한 개방형 표준(RFC 7519)이다.

"전 세계 개발자들이 '이렇게 만들자'고 약속한(RFC 7519)
가볍고(JSON) 조작이 불가능한 디지털 서명

  • Header: 토큰의 타입과 사용된 암호화 알고리즘 정보

  • Payload: 실제 전달할 데이터(사용자 정보 등)

  • Signature: HeaderPayload를 조합해 만든 보안 코드 (위변조 방지 핵심)


JWT의 3단 구조: 왜 점(.)으로 나뉠까?

JWT는 세 부분으로 구성되며, 각 부분은 '마침표(.)'로 구분된다.
Header.Payload.Signature 형식을 가진다.

1. Header (헤더): "이 물건의 정체는 무엇인가?"

  • 헤더는 토큰의 '메타 데이터'를 담고 있다.
    두 가지 핵심 정보를 포함한다.

  • typ: 토큰의 타입을 지정한다. (보통 JWT)

  • alg: 시그니처(서명)를 생성할 때 사용할 해싱 알고리즘을 지정한다.
    (예: HS256, RS256)

  • 비유: 택배 상자 겉면에 붙은 '배송 라벨'과 같다.
    이 상자가 어떤 종류의 물건인지,
    어떤 방식으로 취급(검증)해야 하는지 알려주는 역할이다.


2. Payload (페이로드): "실제 전달할 내용물"

  • 토큰에 담을 실제 정보(클레임)들이 들어있다.
    클레임은 크게 세 종류로 나뉜다.

  • 등록된 클레임: 서비스에서 이미 정의된 정보들
    (예: iss(발행자), sub(제목), exp(만료시간))

  • 공개 클레임(Public): 충돌 방지를 위해 URI 형식으로 정의한 정보

  • 비공개 클레임(Private): 서버와 클라이언트 간에 협의하여
    사용하는 사용자 정의 정보 (예: userId, role)

  • 주의: 페이로드는 암호화된 것이 아니라 Base64Url로 인코딩된 것뿐이다.
    누구나 디코딩하면 내용을 볼 수 있기 때문에,
    비밀번호 같은 민감한 정보는 절대로 페이로드에 넣어서는 안 된다.


3. Signature (시그니처): "이 내용물이 진짜인가?"

  • JWT의 핵심이다.
    헤더의 인코딩 값과 페이로드의 인코딩 값을 합친 뒤,
    "서버만 알고 있는 비밀키(Secret Key)"로 암호화하여 생성한다.

  • 목적: 토큰의 무결성 검증,

    • 만약 중간에 누군가 페이로드의 내용을 1바이트라도 수정한다면,
      서버의 비밀 키로 계산한 시그니처와 일치하지 않게 된다.

    • 서류 봉투에 찍힌 "인감도장" or "봉인 씰"
      봉투 안의 내용(Payload)이 바뀌었는지, 이 도장이 진짜
      우리 회사의 도장(Secret Key)이 맞는지 확인하는 장치이다.


왜 인코딩(Base64Url)을 하는 것인가?

  • JSON 데이터에는 공백이나 특수문자({, }, ", :, , \n 등)가 포함되어 있어
    전송 시 URL이나 HTTP 헤더의 규칙과 충돌하여 데이터가 깨질 위험이 있는데

    이를 방지하기 위해
    전 세계 모든 시스템이 공통적으로
    해석할 수 있는 64개의 안전한 문자(알파벳, 숫자, -, _)로만
    데이터를 변환(Base64Url)
    하여 전송의 안정성과 무결성을 보장하기 위함이다.

왜 세션 대신 JWT를 쓰는 것인가?

Stateless(무상태)

  • 세션: 사용자가 로그인하면 서버(메모리나 DB)에
    "이 사람은 로그인됨"이라는 기록을 남겨야 한다.

  • JWT: 서버는 기록을 남기지 않는다.
    대신 로그인 시 유효기간이 적힌 위조 불가능한 티켓(JWT)
    만들어서 사용자에게 준다.
    이후 사용자가 티켓(JWT)을 제시하면 서버는 자기 장부를 확인하는 게 아니라,
    티켓의 인장(Signature)이 진짜인지만 확인하고 즉시 통과시킨다.

Scale-out (서버 확장)

  • 세션: 서버가 1번부터 10번까지 있을 때,
    1번 서버에서 로그인한 사용자가 2번 서버로 요청을 보내면
    2번 서버는 그 사용자를 모른다(세션 공유 문제 발생).
    이를 해결하려면 별도의 공유 DB(Redis 등)를 구축해야 한다.

  • JWT: 모든 서버가 동일한 비밀 키(Secret Key)만 공유하고 있다면,
    어느 서버로 요청이 가든 그 자리에서 즉시 티켓 검증이 가능하다.
    서버를 수백 대 늘려도 인증 체계가 복잡해지지 않는다.

Decoupled (분리): 역할의 독립

  • 세션: 인증과 서비스 로직이 같은 세션 저장소를
    바라봐야 하므로 강하게 결합된다.

  • JWT: "인증만 해주는 서버"를 따로 만들 수 있다.
    인증 서버가 토큰을 발행해주면, 메일 서비스 서버나 결제 서비스 서버는
    각자 자기 키로 토큰이 맞는지 확인만 하면 된다.
    서로 남의 장부를 뒤져볼 필요가 없어 서비스 간 독립성이 극대화된다.

profile
개발을 즐겨보자.

0개의 댓글