2023. 3. 18. 21:30ㆍWeb
JWT란?
JWT(Json Web Token)는 JSON 포맷을 활용한 토큰 기반의 인증 방식 중 하나이다. RFC 7519에 명시되어 있으며 기존의 Stateful한 세션 방식의 인증 방식과 달리 Stateless한 인증 방식으로 사용된다. JWT가 나온 배경부터 차근차근 살펴보도록 하자.
JWT의 탄생 배경
웹 환경에서 까다로운 부분 중 하나는 로그인 상태를 유지하는 것이다. 사이트에 회원가입한 유저가 로그인한 후 사이트를 돌아다니는데 이동할 때마다 로그인해야 하는 것은 매우 불편하다. 이런 문제를 해결하는 방법으로 전통적인 세션이 있다.
세션은 일반적으로 서버의 메모리에 사용자에 대한 정보들을 저장해두는 방식으로 사용된다. 클라이언트에는 세션 ID를 내려주고 해당 ID에 해당하는 세션의 유무로 사용자를 검증한다. 이런 방법이 있는데 왜 JWT가 나왔을까?
세션의 문제 1. 메모리에 저장된다.
세션은 보통 메모리에 저장한다. 그런데 만약 이용자가 매우 많아서 서버가 버티지 못하고 다운되거나 서버를 재부팅해야 하는 경우가 생긴다면 어떨까? 메모리는 휘발성이기 때문에 컴퓨터가 종료되면 모든 정보가 사라진다. 따라서 기존에 로그인한 유저들은 모두 재로그인해야 하는 상황이 발생한다.
세션의 문제 2. 세션 공유
서비스 규모가 커져서 서버를 늘려야 하는 상황이 생겼다. 그런데 세션은 메모리를 사용한다고 했다. 만약 서버1에 로그인한 유저가 5분 뒤 서버2에 접속한다고 하면 서버2의 메모리에는 유저에 대한 세션이 없기 때문에 문제가 발생한다. 이러한 문제를 해결하기 위해 Redis나 Memcached와 같은 In-Memory DB를 사용하여 세션을 관리하는 방법이 있다.
문제 원인 - 서버 측에서 인증 정보를 관리한다.
이런 문제는 사용자에 대한 인증 정보를 서버 측에서 관리하기 때문에 발생한다. 만약 클라이언트에서 정보를 가지고 있다면 서버에서는 이런 정보를 관리할 필요가 없기 때문에 세션 관리와 같은 문제가 사라지고 인증이 간단해진다. JWT는 이러한 문제를 해결하기 위해 개발된 인증 방식이다. 즉 클라이언트(브라우저)에서 정보를 가지고 있고 서버에서는 관리하지 않는다.
JWT 구조
JWT는 크게 헤더(header), 페이로드(payload), 시그니처(verify signature)의 3부분으로 구분된다.
헤더
해당 토큰의 타입과 암호 알고리즘 종류에 대한 정보가 들어있다.
{
"alg": "HS256",
"type": "JWT"
}
alg
: 시그니처를 만드는 암호 알고리즘의 종류를 나타낸다.type
: 토큰의 타입을 나타낸다. 항상 JWT로 고정이다.
작성된 헤더는 Base64Url로 인코딩된다.
페이로드
실제로 정보를 담고 있는 부분이다. 담고 있는 정보를 클레임(claim)이라고 부른다. 즉 페이로드는 클레임으로 구성되어 있다.
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
페이로드 또한 Base64Url로 인코딩된다.
시그니처
헤더와 페이로드를 Base64Url로 인코딩한 후에 서버에 있는 비밀 키를 사용하여 alg
에 명시한 알고리즘으로 수행한 값이다.
// 인코딩된 헤더 + . + 인코딩된 페이로드, 비밀 키를 통해 알고리즘을 수행
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
이렇게 만들어진 값은 다음과 같은 형태를 띄게 된다.
aaaa.bbbb.cccc
각 부분은 .으로 구분되며 Base64Url로 인코딩된다. 그리고 HTTP 헤더에는 다음과 같이 담긴다.
Authorization: Bearer aaaa.bbbb.cccc
이렇게 전달된 헤더는 서버 측에서 검증하여 사용자 인증을 수행한다.
세션과 JWT의 과정
세션
- 서버 측에서 세션을 생성 및 관리하고 인증 및 인가를 수행한다.
- Stateful하다. → 클라이언트의 상태가 계속 서버 측에서 유지되고 있다.
JWT
- 서버 측에서는 처음 토큰을 생성하기만 하고 클라이언트에 내려보낸다.
- 다음부터는 토큰에 대한 검증만 수행하고 별다른 관리는 하지 않는다.
- Stateless하다. → 서버가 클라이언트의 상태를 계속 유지하고 있지 않는다.
JWT 장단점
장점
- 서버에서 관리하던 정보를 클라이언트로 옮기므로 서버 측 부하가 경감된다.
- 세션으로 관리할 때의 문제점(세션 공유 등)을 신경쓰지 않아도 된다.
단점
- 토큰이 클라이언트에 저장되기 때문에 중요 정보를 담기 부담된다.
- 토큰이 탈취당하면 해커가 유저 행세를 할 수 있게 되므로 위험하다.
- 데이터에 많은 내용이 들어가면 그 데이터가 네트워크에 부하가 걸릴 수 있다.
- 페이로드는 암호화된 것이 아니기 때문에 네트워크 상에서 탈취당하면 그 내용이 노출된다.
💡 토큰의 단점을 완화하기 위해 만료 시간을 짧게 두고 RefreshToken을 발급하는 방법도 존재한다. 하지만 이 또한 완벽한 해결책은 아니다.