Spring

JWT

진공청소ㄱl 2025. 2. 13. 01:09

JWT(Json Web Token)


 

JWT(Json Web Token)은 JWT는 정보를 JSON 객체로 안전하게 전송하기 인터넷 표준 인증 방식이다. 말 그대로 인증에 필요한 정보들을 Token에 담아 암호화시켜 사용하는 토큰이다.

 

HTTP는 서버-클라이언트 구조에서 Stateless(무상태) 방식을 지향하는데, 이는 서버가 클라이언트의 상태 정보를 저장하지 않는다는 의미이다. 이러한 특성은 서버의 확장성을 높여 대량의 트래픽에도 효과적으로 대응할 수 있게 하며, 특정 데이터베이스 서버에 의존하지 않고도 사용자 인증이 가능하다는 장점이 있다.

 

하지만 Stateful(세션) 방식과 비교했을 때, 클라이언트와 서버 간에 더 많은 양의 데이터가 반복적으로 전송되어야 하므로 네트워크 성능 저하가 발생할 수 있으며, 데이터가 매 요청마다 전송되기 때문에 데이터 노출로 인한 보안 위험이 존재한다는 단점도 있다.

 

이러한 단점을 보완하기 위해 JWT로 데이터 압축 및 서명를 위하여 JWT를 사용한다.

 

JWT 구조


 

JWT는 헤더(header), 페이로드(payload), 서명(signature) 세 부분으로 구성되어있다.

 

헤더(header)

 

헤더는 JWT의 첫 번째 구성 요소로, 토큰의 유형과 사용된 서명 알고리즘을 지정하는 메타데이터를 포함한다. 주로 두 가지 정보를 담고 있는데, 하나는 토큰의 유형(typ)을 나타내는 JWT이고, 다른 하나는 사용된 해시 알고리즘(alg)을 나타낸다. 일반적으로 HMAC SHA256 또는 RSA와 같은 알고리즘이 사용된다.

 

 

페이로드(payload)

 

페이로드는 JWT의 두 번째 부분으로, 실제로 전달하고자 하는 데이터를 포함한다. 이 데이터는 클레임(claim)이라 불리는 정보의 조각들로 구성되는데, 저장되는 정보에 따라 등록된 클레임, 공개 클레임, 비공개 클레임으로 나뉜다.

 

등록된 클레임은 JWT 표준에서 정의한 미리 정해진 클레임들이다. 예를 들어, 토큰 발행자(iss), 만료 시간(exp), 발행 시간(iat) 등이 있다. 공개 클레임은 사용자가 정의할 수 있는 클레임으로, 충돌을 방지하기 위해 URI 형식을 사용한다. 비공개 클레임은 당사자들 간에 정보를 공유하기 위해 생성된 커스텀 클레임이다.

 

서명(signature)

서명은 JWT의 마지막 부분으로, 토큰의 무결성을 검증하는데 사용된다. 서명은 인코딩된 헤더, 인코딩된 페이로드, 비밀키를 사용하여 생성된다. 헤더에서 지정한 알고리즘을 사용하여 이 세 가지 요소를 결합하여 해시를 생성한다.

 

서명의 주요 목적은 메시지가 도중에 변경되지 않았음을 확인하는 것이다. 서버는 토큰을 받았을 때 같은 알고리즘과 비밀키를 사용하여 서명을 다시 생성하고, 이를 토큰의 서명부분과 비교한다. 만약 두 서명이 일치하지 않는다면, 이는 토큰이 변조되었다는 것을 의미한다.

 

JWT의 동작 방식


 

1. 로그인 및 토큰 발급 과정

 

사용자가 아이디/비밀번호로 로그인을 시도하면, 서버는 이를 검증한 후 JWT를 생성한다. 생성된 JWT는 클라이언트에게 반환되며, 클라이언트는 이를 로컬 스토리지나 쿠키에 저장한다. 발급되는 토큰은 일반적으로 Access TokenRefresh Token 두 가지이다.

 

2. 인증이 필요한 요청 처리

 

클라이언트는 이후 인증이 필요한 API를 호출할 때마다 저장된 JWT를 요청 헤더에 포함시켜 전송한다. 일반적으로 'Authorization: Bearer {token}' 형식으로 전송되며, 서버는 전달받은 토큰의 유효성을 검증한 후, 요청을 처리한다.

 

3. 토큰 검증 및 응답

 

서버는 받은 JWT의 서명을 검증하고, 토큰이 만료되지 않았는지 확인한다. 검증이 성공하면 요청을 처리하고 응답을 반환하며, 실패하면 401/403 등의 에러 응답을 반환한다. Access Token이 만료된 경우, Refresh Token을 사용하여 새로운 Access Token을 발급받을 수 있다.

 

Access Token과 Refresh Token의 이해


 

인증 시스템에서 단일 토큰만 사용할 경우, 보안과 사용자 경험 사이에서 딜레마가 발생한다. 토큰의 유효 기간을 길게 설정하면 사용자는 편리하지만 보안에 취약해지고, 짧게 설정하면 보안은 강화되지만 사용자가 자주 로그인해야 하는 불편함이 생긴다. 이러한 문제를 해결하기 위해 Access Token과 Refresh Token을 분리하여 사용한다.

 

Access Token의 역할

 

Access Token은 실제로 리소스에 접근하기 위한 임시 인증 수단이다. 짧은 유효기간(보통 30분~2시간)을 가지며, 매 API 요청시 헤더에 포함되어 전송된다. 유효기간이 짧기 때문에 토큰이 탈취되더라도 피해를 최소화할 수 있다. 주로 JWT 형식으로 구현되며, 서버는 이 토큰을 검증하여 사용자의 요청을 승인하거나 거부한다.

 

Refresh Token의 역할

 

Refresh Token은 Access Token이 만료되었을 때 새로운 Access Token을 발급받기 위한 용도로 사용된다. 비교적 긴 유효기간(보통 2주~1달)을 가지며, 보안이 중요하기 때문에 HttpOnly 쿠키와 같은 안전한 저장소에 보관된다. 서버 측에서도 데이터베이스에 저장하여 관리하며, 토큰이 탈취되었을 피해를 최소할 수 있다.

 

이러한 이중 토큰 시스템은 보안과 사용자 경험을 모두 개선한다. Access Token의 짧은 유효기간으로 보안을 강화하면서도, Refresh Token을 통해 자동으로 새로운 Access Token을 발급받을 수 있어 사용자가 빈번하게 로그인할 필요가 없다.

 

하지만 이러한 방법에도 단점이 존재한다. 위와 같은 방법으로 설계를 하면 Refresh Token을 데이터베이스에 저장하여 관리해야 한다. 이는 결국 서버에 상태를 저장해야 하므로 완전한 Stateless를 달성할 수 없게 된다.

 

JWT 동시 로그인 제한에 대한 개인적인 생각


 

결론부터 말하자면, 동시 로그인 제한을 구현하려면 JWT를 사용하지 말아야 한다고 생각한다. JWT를 사용하면서 동시 로그인을 제한하기 위해서는 Access Token을 데이터베이스에 저장하고 관리해야하기 때문이다.

 

예를 들어, 사용자가 로그인할 때마다 새로운 Access Token을 발급하고 이를 데이터베이스에 저장한다. 그리고 클라이언트가 API 요청을 할 때마다 전송하는 Access Token이 데이터베이스에 저장된 토큰과 일치하는지 확인한다. 만약 다른 기기에서 같은 계정으로 로그인하면, 새로운 Access Token이 발급되고 데이터베이스의 기존 토큰은 갱신된다. 이렇게 되면 이전 기기의 Access Token은 더 이상 유효하지 않게 되어 동시 로그인을 효과적으로 제한할 수 있다.

 

이러한 방식은 JWT의 Stateless 특성을 완전히 포기하게 된다. 차라리 세션을 쓰는게 더 나은 방식이라고 생각한다.

 

참고

JWT란 무엇인가?

 

JWT란 무엇인가?

JWT(Json Web Token) > 정보를 비밀리에 전달하거나 인증할 때 주로 사용하는 토큰으로, Json객체를 이용함 JWT는 Json Web Token의 약자로 일반적으로 클라이언트와 서버 사이에서 통신할 때 권한을 위해

velog.io

우리는 왜 JWT를 사용하는가? / JWT 사용 이유

 

우리는 왜 JWT를 사용하는가? / JWT 사용 이유

서론CS 스터디를 준비하다가 웹 보안에 대한 주제로 스터디를 진행하기로 하였다. 그 중 JWT에 대한 내용을 조사하다가 고민해본 점을 정리한다. What is JWTJSON Web Token의 준말입니다. 자바스크립트

ko.puleugo.dev

최진영JWT(Json Web Token) 알아가기

 

JWT(Json Web Token) 알아가기

jwt가 생겨난 이유부터 jwt의 실제 구조까지 | 사실 꾸준히 작성하고 싶었던 글이지만 JWT를 제대로 개념을 정리하고 구현을 진행해본 적이 없었는데 리얼월드 프로젝트를 진행하면서 JWT에 대한

brunch.co.kr