JWT (JSON WEB TOKEN)
JWT는 JSON 객체에 정보를 담아 이를 토큰으로 암호화하여 전송할 수 있는 기술을 의미합니다.
클라이언트와 서버 간의 안전한 정보 교환을 위해 사용하는 토큰이라고 생각 하시면 됩니다.
기본 흐름
JWT 생성 & 검증
JWT의 구성
JWT는 헤더, 페이로드 서명 구조로 이루어져 있고, 각각은 .(점)으로 구분 됩니다.
1. Header
- JWT임을 명시
- 사용된 암호화 알고리즘
2. Payload
- 정보 ( 사용자의 이름, 이메일, 권한, 토큰 만료시간 등)
3. Signature
- 암호화알고리즘((BASE64(Header)) + (BASE64(Payload)) + 비밀키)
❗️주의점
내부 정보를 단순 BASE 방식으로 인코딩하기 때문에 외부에서 쉽게 디코딩 할 수 있기 때문에 패스워드와 같은 민감한 정보를 담으면 안되고, 단순히 "식별할 수 있는" 정보만 담아야 합니다.
이를 통해 JWT를 사용하는 두가지 목적을 알 수 있습니다.
1. Payload를 통해 사용자 정보 확인
2. Signature을 통해 신뢰 할 수 있는(서버에서 발급한) 토큰인지 확인
JWT 암호화 방식
JWT의 암호화 방식은 크게 단방향 암호화와 양방향 암호화로 나눌 수 있습니다.
1. 단방향
- 한 번 암호화하면 되돌릴 수 없는 방식입니다.
- 입력 값이 동일하면 항상 같은 출력 값이 생성되기 때문에 단순 데이터 변조 여부를 검증하는데 사용합니다.
2. 양방향
- 암호화된 데이터를 다시 원래 값으로 복구할 수 있는 방식입니다.
- 대칭키 방식과 비대칭키 방식으로 나눌 수 있습니다.
구분 | 대칭키(HS256) | 비대칭키(RS256) |
키 개수 | 1개 (Secret Key) | 2개 (Private Key / Public Key) |
JWT 검증 방식 | 서버에서 비밀키 검증 | 클라이언트가 공개키로 검증 |
API 제공자의 부담 | 모든 요청을 검증해야 함. (서버 부담 큼) | JWT 생성만 하면 됨 . (서버 부담 적음) |
보안성 | Secret Key 유출 시 토큰 위조 가능 | Private Key 유출 시 토큰 위조 가능 |
사용 사례 | 내부 API 인증 | OAuth, 제 3자에게 API를 제공 |
게시판, 로그인 기능이 있는 일반적인 웹 서비스인 경우에는 대칭키를 사용하면 되고,
OAuth 2.0(Google, Kakao 로그인 등)이나 제 3자에게 API를 제공하는 일 이 있는 경우 비대칭키를 사용하면 됩니다.
여기서 말하는 OAuth는 OAuth 제공자(Google, Kakao)를 의미 하는 것 입니다.
필자와 같이 대학생인 경우에는 비대칭키를 직접 사용할 일은 많지 않기 때문에, 일반적인 웹 서비스를 만드는 프로젝트를 하는 경우 대칭키를 활용해서 진행하면 됩니다.
비대칭키 방식에 대해 더 자세히 알고 싶으면 밑에 링크를 참고해주세요.
https://playouss.tistory.com/15
비대칭 키 암호화 방식
비대칭 키 암호화 방식 비대칭 키 암호화 방식은 이름 그대로 서로 다른 두개의 키를 사용하는 암호화 방식입니다.누구나 볼 수 있는 공개키와 본인만 알고 있는 개인키를 사용합니다.두 키는
playouss.tistory.com
JWT 생성 & 검증 예제 코드
자바(Java)로 JWT 생성 및 검증을 구현하였고, JWT 0.11.5 버전을 사용하였습니다.
JWT 암호화 방식은 양방향 대칭키 방식을 사용하였습니다.
JWT의 KEY 생성 코드
import java.security.Key;
private final Key KEY;
/*
* 개발 환경에서는 `application.yml` 또는 `.properties`에서 SecretKey를 설정해도 되지만,
* 실제 운영 서버에서는 환경 변수(ENV VARS)를 사용하여 설정하는 것이 안전하다!!
*/
public JwtProvider(@Value("${jwt.secret}") String secret) {
this.KEY = Keys.hmacShaKeyFor(secret.getBytes());
}
String 타입의 Secret Key를 사용하는 대신, Key 객체로 변환하는 이유는 보안성 강화와 안전한 키 관리를 위해서 입니다.
1. 안전한 키 생성 (길이 보장)
- HS256 알고리즘을 사용할 경우 최소 32바이트 길이의 키가 필요합니다.
- Key 클래스의 hmacShacKeyFor 클래스는 키의 길이가 32바이트 미만이면 예외를 발생시켜 이를 방지해줍니다.
2. 문자열(String) 기반 키의 보안 취약점
- String을 직접 Secret Key로 사용할 경우 메모리에 남아있는 문제가 발생할 수 있지만,
- Key 객체를 사용하면 Heap 영역에서 안전하게 관리할 수 있으며, 필요할 경우 즉시 삭제가 가능합니다.
JWT 생성 코드
private final long ACCESS_TOKEN_EXPIRE_TIME = 1000 * 60 * 60; // 1시간
public String createAccessToken(UserJwtDto userDto) {
Claims claims = Jwts.claims();
claims.put("userName", userDto.getUserName());
claims.put("email", userDto.getEmail());
claims.put("role", userDto.getRole());
return Jwts.builder()
.setClaims(claims) // 사용자 정보 (페이로드)
.setIssuedAt(new Date()) // 토큰 생성 시간
.setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRE_TIME)) // 토큰 만료 시간
.signWith(KEY) // jwt 0.11 이상 버전에서는 KEY 타입을 보고 자동으로 적절한 알고리즘 선택(HS256)
.compact();
}
- Jwt 헤더 부분 같은 경우에는 Jwts.signWith(KEY)를 호출하면, 헤더부분이 자동으로 생성됩니다.
JWT 검증 코드
public boolean validateToken(String token) {
try {
Claims claims = Jwts
.parserBuilder()
.setSigningKey(KEY) // 서명 검증을 위한 KEY 설정
.build()
.parseClaimsJws(token) // 토큰 분석 및 검증
.getBody(); // 페이로드(Claims) 추출
log.info("userName : {}, 토큰 만료시간 : {}", claims.get("userName"),claims.getExpiration());
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
- 위와 같이 토큰으로 부터 페이로드 부분인 Claims를 복호화하여 정보를 꺼낼 수 있습니다.
이 코드에서는 모든 예외처리를 한번에 처리하였는데, JWT 만료, 서명 오류, 변조된 토큰 등 예외를 개별적으로 구분하여 처리하는 방식이 디버깅과 유지보수에 더 좋은 코드입니다.!!
parseClaimsJws(token)이 검증하는 것은 다음과 같습니다.
- JWT 형식이 올바른지 (MalformedJwtException)
- JWT가 만료되지 않았는지 (ExpiredJwtException)
- 서명이 유효한지 (SignatureException)
- 지원되지 않는 JWT인지 (UnsupportedJwtException)
- 토큰이 비어있거나 잘못되었는지 (IllegalArgumentException)
JWT 장점과 단점
JWT 방식은 토큰 기반 인증 방식으로 현재 많이 사용되는 기술 중 하나이지만,
어떠한 경우에 사용해야 하고, 다른 인증 방식들과 비교해서 어떠한 장단점이 있는지 확실히 이해하고 써야 한다고 생각합니다.
장점
- JWT는 인증에 필요한 모든 정보를 담고 있기 때문에 인증을 위한 별도의 저장소가 필요 없다.
- Stateless한 방식이기 때문에 서버 확장이 쉽고, 서버의 부담이 줄어든다. (사용자의 세션을 저장할 필요가 없기 때문)
- 토큰 기반이기 때문에 여러 시스템(서비스)에 접근 및 권한 공유가 가능하다.(쿠키와의 차이)
- 세션 기반 인증과 비교하여 모바일 환경에서 훨씬 유리하다. (모바일 환경에서는 Ip가 자주 변경되면서 세션이 만료될 가능성이 높기 때문)
단점
- 쿠키/세션 방식과 다르게 토큰의 길이가 길어, 인증 요청이 많아질수록 네트워크 부하가 심해진다.
- JWT 서명에 사용되는 Key가 유출되면 인증 시스템 전체가 무너지게 된다.
- 클라이언트가 JWT를 보관해야 되기 때문에 클라이언트 쪽에서도 보안에 신경써야 한다.
- 토큰을 탈취당한다면 토큰이 만료될 때 까지 사실상 대처가 불가능하다. (블랙리스트 관리 + Refresh Token으로 보완 가능)
'Server' 카테고리의 다른 글
비대칭 키 암호화 방식 (0) | 2025.04.02 |
---|