세션 기반 인증과 토큰 기반 인증, 그리고 JWT

·2023년 12월 3일
0

Spring Boot

목록 보기
15/21
post-thumbnail

🥊 세션 기반 인증 vs 토큰 기반 인증

사용자가 서버에 접근할 때 이 사용자가 인증된 사용자인지 확인하는 방법은 다양하다. 대표적으로 세션 기반 인증과 토큰 기반 인증이 있다. 이 두 가지 방법에 대해 각각 알아보도록 하자.

세션(서버) 기반 인증

세션 기반 인증은 사용자의 인증 정보가 서버의 세션 저장소에 저장되는 방식이다. 예를 들어 사용자가 로그인을 하면, 해당 인증 정보를 서버의 세션 저장소에 저장하고 사용자에게는 저장된 세션 정보의 식별자인 Session ID를 발급한다. 발급된 Session ID는 브라우저에 쿠키 형태로 저장되지만 실제 인증 정보는 서버에 저장되어 있다.

브라우저는 인증 절차를 마친 이후 요청마다 HTTP Cookie 헤더에 Session ID를 함께 서버로 전송한다. 서버는 요청을 전달받고, Session ID에 해당하는 세션 정보가 세션 저장소에 존재한다면 해당 사용자를 인증된 사용자로 판단한다.

스프링 시큐리티에서는 기본적으로 세션 기반 인증을 제공해 준다. 이전 포스팅에서 구현했던 로그인/로그아웃, 회원 가입 기능(누르면 이동😆)은 바로 이 세션 기반 인증을 사용했다.

토큰 기반 인증

그렇다면 토큰 기반 인증이란 뭘까? 토큰 기반 인증은 인증 정보를 클라이언트가 직접 소유하고 있는 방식이다. 이때 인증 정보가 토큰의 형태로 브라우저의 로컬 스토리지(또는 쿠키)에 저장된다. 토큰의 종류에 따라 다르겠지만, 대표적인 토큰인 JWT의 경우 디지털 서명이 존재해 토큰의 내용이 위·변조되는지 서버 측에서 확인할 수 있다.

토큰 기반 인증에서는 사용자가 가지고 있는 토큰을 HTTP Authorization 헤더에 실어 보낸다. 이 헤더를 수신한 서버는 토큰이 위·변조되었거나, 만료 기간이 다 되지 않았는지 확인한 후 토큰에 담겨 있는 사용자 인증 정보를 확인해 사용자를 인가한다.

즉, 서버는 토큰만 보고 이 사용자가 유효한 사용자인지 검증할 수 있는 것이다.

토큰 기반 인증의 특징

1. 무상태성

사용자의 인증 정보가 담겨 있는 토큰이 서버가 아닌 클라이언트에 있으므로 서버에 저장할 필요가 없다. 서버에 데이터를 유지하려면 그만큼 자원을 소비해야 하는데, 토큰 기반 인증에서는 클라이언트에서 인증 정보가 담긴 토큰을 생성하고 인증한다. 따라서 클라이언트에서는 사용자의 인증 상태를 유지하면서 이후 요청을 처리해야 하는데, 이것을 상태 관리라고 한다.

이렇게 하면 서버 입장에서는 클라이언트의 인증 정보를 저장하거나 유지하지 않아도 되기 때문에 완전한 무상태로 효율적인 검증을 할 수 있다!

2. 확장성

무상태성은 확장성에 영향을 준다. 서버를 확장할 때 상태 관리를 할 필요 없으니 서버 확장에도 용이한 것이다. 예를 들어 카카오 로그인, 구글 로그인 등 토큰 기반 인증을 사용하는 다른 시스템에 접근해 로그인 방식을 확장할 수 있고, 이를 활용해 다른 서비스에 권한을 공유할 수도 있다.

3. 무결성

토큰을 발급한 이후에는 토큰 정보를 변경하는 행위를 할 수 없다. 즉, 토큰의 무결성이 보장되는 것이다. 만약 누군가가 토큰을 한 글자라도 변경한다면 서버에서는 유효하지 않은 토큰이라고 판단한다.

리프레시 토큰

그런데 만약 누군가가 사용자의 토큰을 탈취하는 일이 일어났다. 토큰은 이미 발급되면 자체로 인증 수단이 되므로 서버는 토큰과 함께 들어온 요청이 토큰을 탈취한 사람의 요청인지 확인할 수가 없다.

그럼 토큰의 유효 기간을 아주 짧게 만들면 어떨까? 그렇다면 사용자 입장에서 발급받은 토큰을 너무 짧은 시간만 사용할 수 있으니 불편함을 유발할 것이다. 이러한 불편한 지점을 해결하기 위해 리프레시 토큰이 등장한다.

리프레시 토큰은 액세스 토큰과 별개의 토큰이다. 사용자를 인증하기 위한 용도가 아닌 액세스 토큰이 만료되었을 때 새로운 액세스 토큰을 발급하기 위해 사용한다. 액세스 토큰의 유효 기간을 짧게 설정하고, 리프레시 토큰의 유효 기간을 길게 설정하면 공격자가 액세스 토큰을 탈취해도 몇 분뒤에는 사용할 수 없는 토큰이 되므로 안전성이 증진된다! ✨


👀 이제 JWT에 대해 알아보자!

JWT는 위에서 언급한 것처럼 토큰 기반 인증의 한 종류이다. 발급받은 JWT를 이용해 인증하려면 HTTP 요청 헤더 중에 Authorization 키값에 Bearer + JWT 토큰값을 넣어 보내야 한다.

그렇다면 JWT의 구조는 어떻게 생겼을까?

JWT의 구조

aaaaa . bbbbbb . cccccc
 헤더     내용     서명

헤더

토큰의 타입과 해싱 알고리즘을 지정하는 정보를 담는다.

헤더의 구성

이름설명
typ토큰의 타입을 지정한다. JWT라는 문자열이 들어간다.
alg해싱 알고리즘을 지정한다.
{
	"typ": "JWT",
    "alg": "HS256"
}

위 예시는 JWT 토큰과 HS256 해싱 알고리즘을 사용한다는 뜻이다.

내용

토큰과 관련된 내용을 담는다. 내용의 한 덩어리를 클레임이라고 부르며, 클레임은 키값의 한 쌍으로 이루어져 있다. 클레임은 등록된 클레임, 공개 클레임, 비공개 클레임으로 나누어진다.

  • 등록된 클레임은 토큰에 대한 정보를 담는 데 사용된다.
이름설명
iss토큰 발급자(issuer)
sub토큰 제목(subject)
aud토큰 대상자(audience)
exp토큰의 만료 시간(expiration)
nbf토큰의 활성 날짜와 비슷한 개념(Not Before)
iat토큰이 발급된 시간(issued at)
jtiJWT의 고유 식별자
  • 공개 클레임은 공개되어도 상관없는 클레임이다.
    충돌을 방지할 수 있는 이름을 가져야 하며, 보통 클레임 이름을 URI로 짓는다.

  • 비공개 클레임은 공개되면 안 되는 클레임이다.
    클라이언트와 서버 간의 통신에 사용된다.

{
	"iss": "abc@mail.com", // 등록된 클레임
    "iat": 1622370878, // 등록된 클레임
	"exp": 1622372678, // 등록된 클레임
	"https://abc.com/": true, // 공개 클레임
	"email": "abc@mail.com", // 비공개 클레임
	"hello": "안녕!", // 비공개 클레임
}

서명

해당 토큰이 조작되었거나 변경되지 않았음을 확인하는 용도로 사용된다. 헤더의 인코딩 값과 내용의 인코딩 값을 합친 후에 주어진 비밀키를 사용해 해시 값을 생성한다.


profile
풀스택 개발자 기록집 📁

0개의 댓글