스터디에서 쿠키와 세션방식에 대해서 함께 토론하던 중 토큰 방식에 대한 얘기가 나왔다.
토큰에 대해 얘기하다보면 빠지지 않고 나오는 주제인 JWT 에 대해 공부해보았다.
맨날 안다고 하면서 잘 모르는 나
Session vs Token. (with JWT)
먼저 웹 서버에서 Session 기반으로 인증하는 시나리오 를 생각해보자.
- 유저 로그인
- 로그인 성공 시 Session 을 서버 단(메모리, DB 등)에 저장
- Session ID 를 클라이언트로 전송, 클라이언트는 Session ID 를 Cookie 로 저장
- 브라우저는 매 요청마다 request 에 Session ID 를 쿠키에 담아 전송
- 서버는 Session ID 가 일치하는지 확인
Session 기반 인증의 장점 은 아래와 같다.
- 서버 쪽에서 사용자 로그인 상태 확인이 쉬움
- 클라이언트측 변조에 영향이 적고 상대적으로 안전
- 토큰 방식에 Signature 등 부가 정보 ❌, 주고 받는 데이터가 적음
그에 비해 단점 은 아래와 같다.
- 대규모 트래픽이 들어올 시 메모리에 저장되는 Session 정보로 인해 성능 ⬇️
- Redis 와 같은 메모리 관리 시스템이 필요
- 메모리에 저장된 Session 정보는 휘발성.
- 디스크나 DB 에 저장하기에는 I/O 작업 시간 소요.
- 쿠키는 단일 도메인에서만 작동 → 여러 도메인에서 사용할 경우 따로 관리 필요
이에 비해 토큰 방식은 이러한 단점들을 보완할 수 있다.
JWT(Json Web Token)는 Json 포맷으로 사용자 속성을 저장하는 Claim 기반의 Web Token 이다.
JWT 는 Self-Contained 방식으로 정보를 안전하게 전달한다.
Self-Contained : 토큰이 자체적으로 모든 필요한 정보를 가지고 있는 것 !
JWT 구조
JWT 는 Header
, Payload
, Signature
의 3가지 부분으로 나누어지고, 각각 ‘.’ 구분자를 사용해 구분된다.
각 부분은 Json 형태를 Base64 로 encoding 되어 표현된다.
Header
JWT 의 헤더는 typ
, alg
두 필드로 구성된다.
{
"alg": "HS256",
"typ": "JWT"
}
alg
는 뒤에 나올 Signature
를 Hashing 할 알고리즘이 지정되는 필드이다.
Signature 와 토큰 검증에 사용된다.
예시 : HS256, RSA
Payload
Payload 에는 Claim 이 담겨있고, Claim 은 총 3가지로 나누어진다.
Claim : 토큰에 포함된 정보를 나타내는 key-value 쌍
- Registered Claim (등록된 Claim)
표준으로 정의된 클레임들.
iss토큰 발급자
, sub토큰 주제
, exp만료시간
, iat발급시간
등이 있다. - Public Claim (공개 Claim)
사용자 정의 클레임. 어플리케이션에 필요한 정보를 담을 수 있다.
충돌을 방지하기 위해 이름으로 URI 형식을 사용하거나, IANA JWT Claims Registry 라는 곳에
직접 Claim 을 등록해야 한다.
{
"https://blog.jujuwon.dev": true
}
- Private Claim(비공개 Claim)
역시 사용자 클레임. 서버와 클라이언트 사이에 협의된 Cliam 으로 공개 Claim 과 충돌이 나지 않게 사용하면 된다.
{
"user_id": "123123123",
"user_age": 26
}
Signature
Signature 는 토큰을 인코딩하거나 토큰의 유효성 검증을 할 때 사용하는 암호화 코드이다.
Base64로 인코딩된 헤더와 페이로드를 특정 암호화 알고리즘과 서버의 비밀키를 이용해서 암/복호화한다.
이 Signature 를 통해서 헤더나 페이로드가 변조되었는지 검증할 수 있다.
HMAC SHA256 을 사용하는 Signature 생성 로직을 pseudo-code 로 나타내면 아래와 같다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
대표적인 암호화 알고리즘은 HS256과 RSA는 공부해서 추가해야지 …