JWT를 이해하기 전에, 먼저 쿠키와 세션에 대해서 알아야 한다.
사용자가 애플리케이션을 사용할 때, 각 기능을 호출할 때마다 인증을 받는 것은 매우 귀찮을 것이다. HTTP는 Stateless 하기 때문에, 매 호출마다 인증을 받아야 한다.
위와 같은 문제점을 해결하기 위해 쿠키와 세션을 사용한다.
쿠키란?
웹 브라우저에 저장되는 작은 데이터 조각
만료시점이 지나면 자동으로 삭제된다.
쿠키는 다음과 같은 과정으로 작동한다.
세션이란?
서버에서 관리되는 사용자와의 대화 상태
세션은 쿠키를 기반으로 작동한다!
세션은 다음과 같은 과정으로 작동한다.
가장 큰 차이점은, 사용자 정보의 저장 위치이다.
라이프 사이클도 다르다.
세션의 동작 과정을 더 자세히 알아보자.
Session ID 발급 과정
1. 클라이언트가 서버에 페이지를 요청
2. 서버는 세션 ID를 생성하고, 사용자 정보를 저장할 공간을 미리 만들어 둔다.
3. 세션 ID가 포함된 쿠키를 Header에 넣어서 응답
4. 클라이언트는 웹 브라우저에 세션 ID가 들어있는 쿠키를 보관
로그인 과정
1. 클라이언트가 서버에 로그인 요청
2. 서버는 사용자가 회원가입이 되어있는지 확인(인증)
3. 인증된 사용자라면, 해당 사용자의 정보를 세션 ID와 함께 저장
4. 응답 - 메인페이지로 이동
위의 두 과정을 거치면, 세션 ID만 있어도 인증을 받을 수 있다.
예를 들어, 사용자 정보를 요청하는 HTTP Request를 세션 ID와 함께 서버에 보내면, 서버는 세션 영역에서 해당 세션 ID에 맞는 사용자 정보를 찾는다.
만약, 서버가 여러대라면?
수강신청 서버 A, B, C가 존재한다.
로드밸런싱을 사용해서 각 서버에 적절하게 부하를 분산시킨다고 가정해보자.
이러한 문제점을 해결하기 위해서 다음과 같은 방법들을 사용할 수 있다.
해결방법 | 기능 |
---|---|
Session Stickiness | 로드 밸런서가 특정 사용자의 요청을 항상 같은 서버로 전달하도록 설정 예를 들어, 철수가 서버 B에 로그인하면, 이후의 모든 요청은 서버 B로 전달된다. |
세션 정보 중앙 저장 | 세션 정보를 중앙 저장소에 저장하여 모든 서버가 동일한 세션 정보를 공유하도록 한다. - DB 중앙 저장소: 매 로그인마다 I/O가 필요해서 성능이 낮음 - 인메모리 중앙 저장소(Redis): DB 저장소보다 빠름 |
그리고, 해결 방법이 한 가지 더 있다.
바로 JWT를 사용하는 것이다.
JWT (JSON Web Token)
: JSON 형식의 정보를 사용하여 클라이언트와 서버 간에 안전하게 정보를 전송하는 데 사용되는 표준 웹 토큰
JWT는 점(.)으로 구분된 세 부분으로 구성된다.
구성요소 | 설명 |
---|---|
Header | 아래와 같은 정보를 포함한다. - 토큰의 유형: JWT - 사용된 해싱 알고리즘: ex) HMAC SHA256 |
Payload | 토큰에 포함될 실제 데이터(claim) |
Signature | Header와 Payload를 인코딩한 후 비밀키로 해싱한 값 |
위의 3가지 요소들을 Base64로 인코딩 하면 다음과 같은 결과가 나온다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
이것이 바로 JWT 토큰이다.
JWT는 서명(Signature)을 통해 무결성을 보장한다.
즉, 서명을 통해 토큰이 생성된 이후 변경되지 않았음을 보장한다.
Signature = HS256(Base64(Header) + "." + Base64(Payload) + secret)
클라이언트가 JWT 토큰을 보내면, 서버는 토큰을 생성할 때와 똑같은 방식으로 Signature를 만들어내고 JWT 토큰 내부에 존재하는 Signature와 비교한다.
Spring Security를 활용하여 JWT를 구현하는 것은 다음 포스트에서 알아보자.