
이번 글에서는 현대 웹 서비스에서 인증/인가에 널리 사용되는 JWT(JSON Web Token)에 대해 정리해보겠다.
이전 SSO 시리즈에서 다뤘던 OAuth, OIDC에서도 토큰 기반 인증의 핵심으로 JWT가 등장한 바 있다.
1. JWT란?
JWT(JSON Web Token)는 당사자 간에 정보를 JSON 형태로 안전하게 전달하기 위한 자기 완결적(Self-Contained) 토큰 표준(RFC 7519)이다.
"자기 완결적"이라는 말은 토큰 자체에 사용자 정보와 권한 등 필요한 데이터가 모두 담겨 있다는 뜻이다. 서버가 별도로 세션을 저장하지 않아도 토큰만으로 사용자를 식별하고 검증할 수 있다.
- 세션 방식 vs JWT 방식
| 구분 | 세션(Session) 방식 | JWT 방식 |
|---|---|---|
| 상태 저장 | 서버에 세션 저장 (Stateful) | 토큰 자체에 포함 (Stateless) |
| 서버 부하 | 세션 저장소 필요 | 별도 저장소 불필요 |
| 확장성 | 서버 증설 시 세션 공유 필요 | 수평 확장에 유리 |
| 보안 | 서버가 세션 직접 제어 가능 | 토큰 탈취 시 만료 전까지 통제 어려움 |
2. JWT 구조
JWT는 Header, Payload, Signature 세 부분으로 구성되며, 각 부분은 Base64Url로 인코딩되어 점(.)으로 구분된다.
xxxxx.yyyyy.zzzzz
│ │ │
Header Payload Signature
📌 1) Header
토큰의 타입(JWT)과 서명에 사용할 알고리즘 정보를 담는다.
{
"alg": "HS256", // 서명 알고리즘 (HMAC SHA256)
"typ": "JWT" // 토큰 타입
}
📌 2) Payload
실제 전달하려는 데이터를 담는 부분이다. 여기에 담기는 각 항목을 클레임(Claim)이라고 한다.
| 클레임 종류 | 설명 | 예시 |
| 등록된 클레임 | JWT 표준에서 정의한 예약된 필드 | iss, sub, exp, iat |
| 공개 클레임 | 충돌 방지를 위해 URI 형태로 정의 | https://example.com/role |
| 비공개 클레임 | 서버-클라이언트 간 합의한 커스텀 필드 | userId, email |
{
"iss": "https://auth.example.com", // 발급자
"sub": "user123", // 사용자 식별자
"exp": 1714000000, // 만료 시간 (Unix timestamp)
"iat": 1713996400, // 발급 시간
"email": "user@example.com", // 비공개 클레임
"role": "admin" // 비공개 클레임
}
* Payload는 Base64Url로 인코딩된 것이지 암호화된 것이 아니다. 누구나 디코딩하면 내용을 볼 수 있으므로, 민감한 정보(비밀번호 등)는 절대 담으면 안 된다.
📌 3) Signature
Header와 Payload를 합친 후 비밀키(Secret Key)로 서명한 값이다. 이 서명을 통해 토큰이 위변조되지 않았음을 검증한다.
HMACSHA256(
Base64Url(Header) + "." + Base64Url(Payload),
secretKey
)
3. JWT 인증 흐름
JWT를 이용한 일반적인 인증 흐름은 아래와 같다.
- ① 사용자가 ID/PW로 로그인 요청
- ② 서버가 자격증명 확인 후 Access Token(JWT) 발급
- ③ 클라이언트는 이후 요청 시 HTTP 헤더에 토큰을 담아 전송
- ④ 서버는 토큰의 서명을 검증하고 Payload에서 사용자 정보를 확인
- ⑤ 인증 성공 시 요청 처리, 실패 시 401 반환
# HTTP 요청 헤더에 JWT 포함하는 방법
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
4. Access Token & Refresh Token
JWT를 실무에서 사용할 때는 보통 두 가지 토큰을 함께 운용한다.
- Access Token
실제 API 요청에 사용하는 토큰이다. 유효 기간을 짧게(보통 15분~1시간) 설정하여 탈취되더라도 피해를 최소화한다.
- Refresh Token
Access Token이 만료됐을 때 새로운 Access Token을 발급받기 위한 토큰이다. 유효 기간이 길며(보통 7일~30일) 서버 DB에 저장하여 관리한다.
| 구분 | Access Token | Refresh Token |
| 용도 | API 인증 | Access Token 재발급 |
| 유효 기간 | 짧음 (15분~1시간) | 김 (7일~30일) |
| 저장 위치 | 메모리 또는 로컬 | 서버 DB + HttpOnly 쿠키 |
| 탈취 위험 | 높음 (자주 사용) | 상대적으로 낮음 |
5. JWT 보안 주의사항
- alg: none 공격
일부 라이브러리는 Header의 알고리즘이 none으로 설정된 경우 서명 검증을 생략한다. 반드시 서버에서 허용할 알고리즘을 명시적으로 지정해야 한다.
- Payload 민감정보 금지
앞서 언급했듯이 Payload는 누구나 디코딩할 수 있다. 비밀번호, 카드번호 등 민감한 정보는 절대 담지 않는다.
- 토큰 저장 위치
브라우저에서 JWT를 저장할 때 localStorage는 XSS 공격에 취약하다. Refresh Token은 HttpOnly 쿠키에 저장하는 것이 권장된다.
- 짧은 만료 시간 설정
JWT는 한번 발급되면 서버에서 강제 무효화가 어렵다. Access Token의 만료 시간을 짧게 유지하고, Refresh Token 기반의 재발급 구조를 사용하는 것이 좋다.
📌 이번 글 정리
- JWT는 Header.Payload.Signature 세 부분으로 구성된 자기 완결적 토큰이다.
- Payload는 암호화가 아닌 Base64Url 인코딩이므로 민감정보를 담으면 안 된다.
- 실무에서는 Access Token(단기) + Refresh Token(장기) 조합으로 운용한다.
- 토큰은
Authorization: Bearer헤더로 전달하는 것이 표준 방식이다. - 보안을 위해 알고리즘 명시, HttpOnly 쿠키 사용, 짧은 만료 시간 설정을 권장한다.
다음 글에서는 JWT를 실제로 Spring Boot에서 구현하는 방법을 정리해보겠다.
'보안 시스템' 카테고리의 다른 글
| [ SSO ]의 종류 3 ‑ OpenID Connect (OIDC) (0) | 2025.07.29 |
|---|---|
| [ SSO ]의 종류 2 - OAuth (0) | 2025.02.03 |
| [ SSO ]의 종류 1 - SAML (0) | 2025.02.02 |
| [ SSO ] 기본개념 정리 (0) | 2025.02.01 |