🔐 HTTP의 특징 및 쿠키(Cookie)와 세션(Session)의 등장
JWT를 소개하기 전에 HTTP의 특징과 쿠키와 세션의 등장 배경에 대하여 알아보자.
기본적으로 HTTP 프로토콜 환경은 'Connectionless', 'Stateless'한 특성을 가지고 있다.
- Connectionless(비연결성)
- 클라이언트가 서버에 요청 후, 요청에 대한 응답을 받으면 바로 TCP/IP 연결을 끊는다.(연결을 유지하지 않는다.) - Stateless(무상태)
- 서버가 클라이언트의 이전 상태를 보존하지 않는다.
이러한 특성으로 인하여 서버는 클라이언트가 누구인지 매번 확인을 해야하는 번거로움이 있었다.
이를 보완하기 위해서 쿠키와 세션 개념이 도입된 것이다.
🔐 쿠키(Cookie)와 세션(Session)
- 쿠키란?
- 쿠키는 클라이언트(브라우저) 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일이다.
- 사용자 인증이 유효한 시간을 명시할 수 있으며, 유효 시간이 정해지면 브라우저가 종료되어도 인증이 유지된다는 특징이 있다.
- 쿠키는 사용자가 따로 요청하지 않아도 브라우저가 Request Header에 넣은 후 자동으로 서버에 전송한다.
- 쿠키의 동작 방식
- 클라이언트가 서버에 요청을 보내면 서버는 쿠키를 생성한 후 HTTP 헤더에 쿠키를 포함시켜 응답한다.
- 클라이언트는 요청마다 응답받았던 쿠키 정보를 함께 보낸다.
- 서버는 전달받은 쿠키의 정보로 클라이언트를 식별한다.
- 세션이란?
- 세션은 쿠키를 기반하고 있지만, 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 세션은 서버 측에서 관리한다.
- 서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하며,
웹 브라우저가 서버에 접속해서 브라우저를 종료할 때까지 인증상태를 유지한다. - 사용자에 대한 정보를 서버에 두기 때문에 쿠키보다 보안상 좋지만, 수가 많아질수록 서버 메모리를 많이 차지하게 된다.
- 클라이언트가 서버로 요청을 보내면, 서버는 클라이언트에게 유일한 ID를 부여하는데 이것이 세션 ID이다.
- 세션의 동작 방식
- 클라이언트가 서버에 요청을 보내면 서버는 세션과 이에 해당하는 세션 ID를 생성하고 이를 저장 후 세션 ID를 응답한다.
- 클라이언트는 요청마다 응답받았던 세션 ID를 쿠키에 담아 함께 전달한다.
- 서버는 세션 ID를 토대로 저장된 세션 정보와 비교하여 클라이언트를 식별한다.
하지만 이러한 방식은 HTTP의 장점이라고 할 수 있는 Statless를 위배하게 된다.
서버의 세션 저장소라는 곳에 SessionID를 저장하는 상황이기 때문에 Stateful 하게 되는 것이기 때문이다.
이러한 단점을 보완하기 위해 등장한 것이 JWT이다.
🔐 JWT(Json Web Token)의 등장
- JWT란?
JWT는 하나의 인터넷 표준 인증 방식으로 인증에 필요한 정보들을 암호화시킨 JSON 형태의 토큰을 말한다.
- JWT를 사용한 인증방식
위에서 알아본 쿠키와 세션을 사용한 인증 방식과는 어떻게 다른지 그림을 통해서 알아보자.
토큰을 사용하면 '쿠키/세션'을 사용한 것과는 다르게 특별한 저장소(세션 저장소)에서 값을 조회해오는 절차가 생략된 것을 볼 수 있다.
즉, Statless한 특징을 지키면서 사용자를 인증할 수 있게 된다는 뜻이다.
어떻게 이러한 것이 가능해진 것인지 JWT에 대하여 자세하게 확인해보자.
🔐 JWT 구조
JWT는 Header, Payload, Signature로 구성되어있으며 각 파트는 점(.)으로 구분된다.
- Header
Header는 토큰의 타입과 해시 암호화 알고리즘으로 구성되어 있다.
- alg는 해시 알고리즘을 나타내며 HMAC, SHA256, RSA와 같은 알고리즘을 사용할 수 있다.
- tpy은 토큰 유형을 나타낸다. - Payload
Payload는 토큰에 사용할 정보의 조각들인 Claim이 담겨있으며, Claim은 3가지로 나뉘어진다.
- Registered claims는 미리 정의된 클레임으로 iss(토큰 발급자), sub(토큰 제목), aud(토큰 대상자), exp(토큰 만료 시간), iat(토큰 발급 시간) 등의 값을 가진다.
- Public claims은 공개용 정보 전달을 위한 클레임으로 사용자가 정의 가능하다.
- Private claims은 비공개 클레임(=사용자 정의 클레임)으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 가진다. - Signature
- 토큰을 인코딩하거나 유효성을 검증할 때 사용하는 고유한 암호화 코드이다. 위에서 살펴본 Header와 Payload의 값을 BASE64로 인코딩한 후 그 값을 Secret Key를 이용해 Header에서 정의한 알고리즘으로 해싱을 하고, 이 값을 다시 BASE64로 인코딩하여 생성한다.
🔐 JWT의 장점과 단점
- 장점
- 인증에 필요한 정보가 토큰에 들어있기 때문에 별도의 저장소가 필요 없다.
- Session에 사용자 정보를 저장할 필요가 없기 때문에 서버측 부담을 줄일 수가 있다.
- Cookie와 Session 사용시 문제점이였던 stateful 특성을 JWT 사용시 stateless하게 가져갈 수 있다.
- HTTP 헤더에 넣어서 쉽게 전달 가능하다. - 단점
- Claim에 넣는 데이터가 많아질수록 토큰의 길이가 길어져 네트워크 대역폭 낭비가 발생할 수 있다.
- 한 번 발급된 토큰의 값은 수정이 불가하며 폐기 또한 불가능하다.
- Payload에 대한 정보가 암호화되는 것이 아니라 단순히 인코딩만 하고 있기 때문에 탈취 당한다면 디코딩을 통해 데이터를 확인할 수 있다.
🔐 JWT 보안 전략
- Refresh토큰의 도입
JWT도 제 3자에게 토큰 탈취의 위험성이 있다.
탈취 당했을 때의 위험을 줄이기 위하여 유효기간을 짧게 선택할 수도 있으나, 이 경우 인증을 자주 받아야하는 불편함이 있다.
이러한 문제점을 보완하기 위하여 토큰을 그대로 사용하는 것이 아닌 Access토큰과 Refresh토큰으로 나누어 이중으로 구성하는 방법이 모색되었다. - Access토큰과 Refresh토큰
- Access토큰 : 요청에 사용되는 토큰으로, 생명주기가 짧기 때문에 탈취 당하더라도 위험성이 낮아진다.
- Refresh토큰 : 만료기간이 짧은 Access토큰을 재발급받기 위한 토큰으로 생명주기가 보다 길다.
정상적인 Refresh토큰을 통해 Access토큰을 재발급 받을 수 있다. - Access토큰과 Refresh토큰을 사용한 인증 절차
- 클라이언트는 ID와 PASSWORD를 사용하여 로그인을 시도한다.
- 서버는 로그인 정보를 토대로 유효한 사용자인지 판단한다.
- 유효한 사용자인 경우, Access토큰과 Refresh토큰을 발급한다.
- 발급한 토큰을 클라이언트로 전달한다.
- 클라이언트는 매 요청마다 발급받은 Access토큰을 헤더에 담아 요청한다.
- 서버는 Access토큰이 유효한 토큰인지 검증한다.
- 유효한 Access토큰이라면 클라이언트의 요청에 응답한다.
- Access토큰이 만료
- [5]번과 동일하게 Access토큰을 헤더에 담아 요청
- 서버는 Access토큰이 유효한지 검증하는 과정에서 만료된 토큰임을 확인한다.
- 서버는 Access토큰이 만료된 토큰이라고 응답을 한다.
- 클라이언트는 최초에 발급받은 Access토큰과 Refresh토큰을 사용하여 서버에 Access토큰 재발급 요청을 한다.
- 서버는 Access토큰과 Refresh토큰이 모두 유효한 토큰이면, 재발급한 Access토큰을 전달한다.
References.
1. kyeo.log - HTTP, Stateless, Connectionless, HTTP 메시지 개념
2. RyanGomdoriPooh - 쿠키와 세션 개념
3. 일상 속 개발록 - JWT(JSON Web Token)과 인증 방식
4. 개발 끄적임 - Access Token, Refresh Token
'Spring' 카테고리의 다른 글
[SpringBoot] REST Docs (0) | 2023.02.19 |
---|---|
[Security] JWT 구현 (0) | 2023.02.16 |
[Spring] 스프링 AOP (0) | 2023.02.07 |
[Spring] 스프링 IoC (0) | 2023.02.05 |
[Spring] 스프링 DI (2) | 2023.02.02 |