JWT는 JSON Web Token의 약자로, 두 시스템 간에 안전하게 정보를 전송하기 위한 컴팩트하고 자가 포함적인 토큰 형식입니다. 보통 인증(Authentication)과 권한 부여(Authorization)를 위해 사용됩니다. JWT는 서명(Signature)을 통해 데이터의 무결성을 보장하며, 클라이언트와 서버 간의 데이터 교환에서 흔히 사용됩니다.
JWT의 구성
JWT는 3개의 부분으로 나눠집니다: 헤더(Header), 페이로드(Payload), 서명(Signature).
1. 헤더 (Header): 토큰의 종류와 서명 알고리즘 정보
2. 페이로드 (Payload): 토큰에 담고자 하는 실제 데이터 (예: 사용자 정보) 암호화되지 않아서 쉽게 디코딩 가능
3. 서명 (Signature): 토큰의 무결성을 보장하기 위해 사용. 비밀 키나 공개/비공개 키 페어를 사용하여 생성
각 부분은 base64url로 인코딩되어 .(점)으로 구분된 하나의 문자열로 결합됩니다.
Header
- JWT의 첫 번째 부분은 헤더입니다. 헤더는 일반적으로 토큰의 타입(JWT)과 서명 알고리즘(HMAC SHA256, RSA 등)을 지정합니다.
- 알고리즘 (Algorithm): 서명을 생성할 때 사용하는 알고리즘 (예: HS256, RS256 등)
- 타입 (Type): JWT라는 토큰 타입을 명시
예시:
{
"alg": "HS256",
"typ": "JWT"
}
- alg: 사용된 서명 알고리즘(HMAC SHA256, RSA 등)
- typ: 토큰의 타입(보통 "JWT")
2. Payload
- JWT의 두 번째 부분은 페이로드입니다. 이 부분에는 클레임(Claim)이라고 불리는 실제 데이터가 포함됩니다. 클레임은 주로 사용자 정보, 만료 시간 등입니다.
- 클레임에는 세 가지 유형이 있습니다:
- 등록된 클레임(Registered Claims): JWT에서 표준화된 클레임 (예: exp, iss, sub, aud 등)
- 공개 클레임(Public Claims): 사용자가 정의한 데이터. 예를 들어, 사용자 이름이나 이메일.
- 비공개 클레임(Private Claims): 두 시스템 간에 합의된 클레임으로, 외부와 공유되지 않습니다.
- 이 데이터는 암호화되지 않기 때문에 누군가 쉽게 읽을 수 있습니다.
예시:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
- sub: 주체(subject) (예: 사용자 ID)
- name: 사용자 이름
- iat: 토큰 발행 시간 (issued at)
3. Signature
- 세 번째 부분은 서명입니다. 서명은 JWT의 헤더와 페이로드를 합쳐서 비밀 키를 이용해 생성된 서명입니다. 서명은 토큰이 변조되지 않았음을 보장하며, 클라이언트와 서버가 동일한 비밀 키를 알고 있어야 합니다.
서명 생성 방법:
- 헤더와 페이로드를 각각 Base64Url로 인코딩합니다.
- HMACSHA256 알고리즘 등을 사용하여 서명을 생성합니다.
- 헤더, 페이로드, 서명을 .(dot)으로 결합하여 최종 JWT 토큰을 생성합니다.
JWT 생성 예시:
<헤더 인코딩>.<페이로드 인코딩>.<서명>
예시 JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWT의 전체적인 흐름
1. 로그인:
- 사용자가 로그인하면 서버는 사용자의 정보를 확인한 후 JWT 토큰을 생성합니다.
- 이 토큰은 사용자의 ID, 권한, 발급 시간, 만료 시간 등 중요한 정보를 포함합니다.
- 이 JWT 토큰은 사용자에게 반환됩니다.
2. 클라이언트는 JWT를 로컬 스토리지나 쿠키에 저장합니다.
3. API 요청:
- 사용자는 API 요청을 할 때 HTTP 헤더에 JWT를 포함시켜 요청합니다.
- 예) `Authorization: Bearer <JWT>`
4 .서버에서 JWT 검증:
- 서버는 요청을 받으면 헤더에서 JWT를 추출하고, 서명과 만료 여부를 확인하여 이 토큰이 유효한지 검증합니다.
- 서명이 유효하고 토큰이 만료되지 않았다면, JWT에 담긴 정보를 이용해 사용자를 인증하고 요청을 처리합니다.
- 그렇지 않으면 401 Unauthorized를 반환합니다.
JWT 검증
서명 검증이란, 서버가 받은 JWT가 실제로 신뢰할 수 있는 토큰인지 확인하는 절차입니다.
이를 통해 클라이언트가 보낸 JWT가 변조되지 않았고, 유효한 토큰인지 판단할 수 있습니다.
서명 검증 과정:
1. JWT 토큰을 디코딩하여 헤더, 페이로드를 추출합니다.
2. 서명 부분을 검증합니다.
- 서버가 가지고 있는 비밀 키 또는 공개 키로 JWT 서명을 확인합니다.
- 서명이 유효하면 토큰이 변조되지 않았다는 것을 보장합니다.
3. 만료 시간 (exp)을 확인하여 토큰이 아직 유효한지 확인합니다.
JWT의 장점
- 자기 포함성 (Self-contained): JWT는 모든 정보를 자체적으로 포함하고 있기 때문에 서버가 별도의 세션을 관리할 필요가 없습니다. 서버는 JWT 자체로 사용자 정보를 확인할 수 있습니다.
- 분산 환경에서 유용: 서버 간에 세션을 공유할 필요 없이 JWT를 통해 인증을 처리할 수 있습니다. 여러 서버가 분산되어 있을 때 유용합니다.
- 스케일링에 유리: JWT는 세션 정보를 서버에 저장하지 않기 때문에, 서버가 수평적으로 확장(Scale)될 때 유리합니다.
- 토큰 만료 시간 설정: 만료 시간을 설정할 수 있어 일정 시간이 지나면 토큰을 자동으로 만료시켜 보안을 강화할 수 있습니다.
JWT의 단점
- 토큰 크기: JWT는 서명과 페이로드를 포함하고 있기 때문에 세션 ID보다 크기가 커질 수 있습니다. 이로 인해 HTTP 요청의 헤더 크기가 커질 수 있습니다.
- 만료된 토큰 관리: JWT는 자기 포함형태로 동작하기 때문에, 한 번 발급된 토큰은 만료되기 전까지 변경할 수 없습니다. 따라서 토큰을 취소하거나 블랙리스트에 추가하는 것이 복잡할 수 있습니다.
- 보안: 비밀 키를 서명하는 데 사용하므로, 만약 비밀 키가 유출되면, 누구나 JWT를 생성할 수 있습니다. 따라서 비밀 키 관리가 매우 중요합니다.
JWT 사용 예시 (Spring Boot)
1. 로그인 후 JWT 발급
- 사용자가 로그인하면, 서버는 JWT를 발급하고 클라이언트에 전달합니다.
서버 코드 예시 (Spring Boot)
@PostMapping("/login")
public String login(@RequestBody User user) {
// 사용자 인증 과정 (이름, 비밀번호 검증 등)
// JWT 생성
String jwt = JwtUtil.generateToken(user);
return jwt; // 생성된 JWT 반환
}
2. JWT를 Authorization 헤더에 포함하여 요청
- 클라이언트는 받은 JWT를 Authorization 헤더에 담아서 서버에 요청을 보냅니다.
클라이언트 요청 예시
GET /protected/resource HTTP/1.1
Authorization: Bearer <JWT>
서버에서 JWT 검증
- 서버는 Authorization 헤더에서 JWT를 추출하여 검증하고, 유효한 경우 요청을 처리합니다.
서버 코드 예시 (Spring Boot)
@GetMapping("/protected/resource")
public ResponseEntity<String> getProtectedResource(@RequestHeader("Authorization") String authHeader) {
String token = authHeader.substring(7); // "Bearer " 제외한 토큰만 추출
if (JwtUtil.isTokenValid(token)) {
return ResponseEntity.ok("Protected resource accessed");
}
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid token");
}
결론
`JWT (JSON Web Token)`은 인증과 권한 부여에서 가볍고 안전한 데이터 전송을 가능하게 해주는 도구입니다. 특히 클라이언트-서버 아키텍처에서 세션 관리를 대체할 수 있는 좋은 방법입니다. 하지만 보안과 토큰 관리에 신경을 써야 하며, 만료된 토큰을 처리하는 방법에 대한 고려도 필요합니다.
JWT의 주요 장점은 자기 포함성, 서버 간 독립성, 빠른 성능 등이지만, 단점으로는 토큰 크기, 만료된 토큰 관리 등의 문제를 고려해야 합니다.
'백엔드 공부일지 > 스프링부트 공부일지' 카테고리의 다른 글
Spring MVC 패턴과 REST API (1) | 2025.04.02 |
---|---|
Spring Boot에서의 CI/CD (1) | 2025.03.28 |