(CS/컴퓨터공학) JWT 완전 가이드 - 개념, 구조, 동작 원리
✨ 개요
JWT(JSON Web Token) 는 인증/인가 정보를 자체 포함(Self-contained) 하는 토큰입니다.
서버는 토큰의 서명(Signature) 만 검증해 신뢰할 수 있으며, DB 조회 없이도 사용자 식별·권한 확인이 가능합니다.
1. 한 장 요약
- 형식:
헤더.header.페이로드.payload.서명.signature(각 부분은 Base64URL 인코딩) - 검증: 서버는 비밀키(HS256) 또는 공개키(RS256/ECDSA) 로 서명을 검증
- 용도: API 인증/인가(Access Token), 세션 대체, 서비스 간 호출
- 주의: 만료/폐기/키회전/저장소(XSS·CSRF) 대책이 핵심
2 구조(Structure)
2.1 Header (메타데이터)
{ "alg": "RS256", "typ": "JWT", "kid": "key-id-2025-01" }
// alg: 서명 알고리즘(예: HS256, RS256, ES256)
// kid: 키 식별자(JWKS 키 회전 시 어떤 키로 서명했는지 표시)
// typ: 보통 "JWT"
2.2 Paylod
{
"iss": "https://auth.example.com", // 토큰 발급자
"sub": "user_123", // 사용자 식별자
"aud": "api.example.com", // 토큰 대상(클라이언트/리소스)
"exp": 1734300000, // 만료 시각(UTC epoch seconds)
"iat": 1734296400, // 발급 시각
"nbf": 1734296400, // 이 시간 전에는 유효하지 않음
"scope": "read:orders write:orders",
"role": "admin",
"jti": "6c1a0e9e..." // 토큰 고유 ID(블랙리스트/재사용 방지에 유용)
}
- 표준 클레임: iss, sub, aud, exp, iat, nbf, jti
- 커스텀 클레임: 도메인 접두사 권장(예: org.example.role)
2.3 Signature
signature = Sign( base64url(header) + "." + base64url(payload), key, alg )
- JWS(서명) 규격을 따릅니다. (암호화가 필요하면 JWE)
3 동작 원리(Flow)
- 로그인: 사용자가 ID/PW 또는 OAuth로 인증
- 발급: 인증 서버가 Access Token(JWT)(수명 짧게)와 Refresh Token(수명 길게)을 발급
- 요청: 클라이언트가 API 호출 시
- Authorization: Bearer
- Authorization: Bearer
- 검증: 리소스 서버는
- 대칭키(HS256): 서버에 저장된 같은 비밀키로 서명 검증
- 비대칭키(RS256/ES256): 공개키(JWKS URL로 배포)로 검증 → 수평 확장에 유리
- 인가: sub/role/scope 등으로 권한 판단
- 갱신: Access 만료 시 Refresh 로 새 Access 발급(토큰 회전/블랙리스트 전략과 함께)
4. 서명 알고리즘 선택
| 알고리즘 | 키 유형 | 장점 | 단점/주의 | 권장도 |
|---|---|---|---|---|
| HS256 | 대칭(Secret) | 간단/빠름 | 모든 검증자가 같은 비밀키 필요(유출시 전체 위험) | 소규모/단일 서비스 |
| RS256 | 비대칭(RSA) | 공개키 배포로 수평 확장 용이 | 개인키 관리/성능 비용 | ✅ 일반 권장 |
| ES256 | 비대칭(ECDSA) | 짧은 키/서명, 성능 우수 | 구현/호환성 점검 필요 | ✅ 권장(현대 환경) |
5. 저장소 선택(웹·모바일)
- 브라우저
- 쿠키(HttpOnly, Secure, SameSite=Lax/Strict): XSS로부터 안전, CSRF 방어는 SameSite/토큰 이중화로
- localStorage/sessionStorage: 접근 쉬우나 XSS에 취약 → 보안 민감 서비스에 비권장
- 모바일 앱: 플랫폼 보안 저장소(안드로이드 EncryptedSharedPreferences/Keystore, iOS Keychain)
6. 만료·갱신·폐기(실무 핵심)
- 짧은 Access(5–15분) + 긴 Refresh(7–30일)
- 토큰 회전(Rotation): Refresh 사용 시 새 Refresh + 이전 것 즉시 폐기
- 블랙리스트/허용리스트 전략
- 로그아웃/강제 로그아웃: jti/세션ID를 서버 저장소(캐시) 에 등록해 잔여 수명 무효화
- 고가용성: Redis 등 공유 저장소 사용
- 범위(Scope)/권한(Role) 는 최소 권한 원칙(Principle of Least Privilege)
7. 보안 오해와 사실
- “JWT는 암호화되어 내용이 보안이다” → ❌ 기본(JWS)은 서명만; 내용은 평문(Base64URL)
- “서명은 검증만 하면 끝” → ◑ aud/iss/nbf/exp 까지 정책적으로 검증해야 안전
- “alg를 none으로 보내면 검증 생략” → 현대 라이브러리는 차단하지만 구버전 취약점 주의
- “쿠키면 CSRF, 헤더면 안전” → ❌ 헤더라도 XSS에 노출되면 탈취 가능. HttpOnly 쿠키 + CSRF 대책이 기본
- “Refresh는 무한히 재사용” → ❌ 회전 + 재사용 탐지(재사용 시 전체 세션 폐기) 도입
8. 실무 체크리스트
- RS256/ES256 + JWKS(키 회전)
- Access 짧게 / Refresh 길게 / 회전 + 재사용 차단
- iss/aud/exp/nbf/iat/jti 검증 로직
- 스코프/권한 최소화 + 서버 측 재검증
- 브라우저는 HttpOnly 쿠키 + SameSite / 모바일은 보안 저장소
- 로그아웃/탈취 사고 대응을 위한 블랙리스트(or 세션 버전)
- TLS 필수(전송 중 탈취 방지) + 적절한 CORS 정책
- 장애/갱신 폭주 대비 토큰 캐싱/서명키 캐시(JWKS)