개발 공부 기록

[Spring] Session 기반과 JWT 기반의 인증 본문

Spring/Development Log

[Spring] Session 기반과 JWT 기반의 인증

나만없서고냥이 2023. 12. 9. 04:47

개인 프로젝트에서 인증 기능을 구현해야 하는데, 이때 SpringBoot에서 인증을 구현하는 주요 방식으로 Session 기반과 JWT(JSON Web Token) 기반이 있습니다. 구현을 하기 전에 두 방식에 대해 어느 정도 짚고 가고 싶었기에 이렇게 포스팅을 하게 되었습니다.

 


✔️ Session 방식이란 ?

우선 session이란, 사용자나 시스템 간의 상호 작용이나 작업을 수행하는 동안 유지되는 일련의 상태를 의미합니다. 보통 이러한 session은 사용자가 어떠한 프로그램에 로그인하거나 접속하여 작업을 시작할 때 시작되고, 사용자가 로그아웃하거나 접속을 종료할 때 끝납니다. 즉, 웹에서의 session은 사용자가 웹사이트에 접속하여 작업을 수행하는 동안 일시적으로 유지되는 상태를 말합니다. 

 

이러한 session을 가지고 로그인이 어떻게 이루어지는지 확인해 봅시다.

 

📝 Session 기반의 동작 방식

1. 클라이언트가 서버에 접속하면, 서버는 고유한 Session ID를 생성하고 이를 쿠키에 담아 클라이언트에게 전송합니다.

2. 이때 쿠키에는 Session ID가 저장되어 있으며, 사용자의 브라우저는 이를 자동으로 저장합니다.

3. 이렇게 Session ID를 저장한 브라우저는 클라이언트가 다음 요청을 보낼 때마다 쿠키가 함께 전송됩니다.

4. 서버는 요청을 받을 때 전송된 쿠키에서 Session ID를 추출하여, 해당 ID에 연결된 session을 찾아 클라이언트의 상태를 유지하고 관리합니다.

5. 로그아웃 시에는 Session ID를 제거하거나 무효화하여 로그인 상태를 종료합니다.

 

위와 같이 사용자는 Session ID를 사용하여 서버에 로그인 상태를 지속하게 됩니다. 서버 측에서 session을 관리하기 때문에 로그인 상태의 유지와 로그아웃 등을 쉽게 관리할 수 있으며, 이러한 Session ID는 쿠키에 저장되므로 클라이언트에게 민감한 정보가 직접적으로 노출되지 않습니다.

 

그러나 문제점은, 서버에서 session을 유지하는 만큼 많은 사용자가 동시에 접속하면 서버의 부하가 증가할 수 있습니다. 이는 session 데이터를 서버 메모리에 저장하고 관리하기 때문인데, 이를 해결하기 위해 데이터베이스나 하드디스크를 사용한다면 서버 메모리에 비해 속도가 저하된다는 또 다른 단점이 존재합니다. 또한, 서비스의 규모가 커 서버를 여러 대 둘 경우, session 정보를 모든 서버에 동기화하는데 어려움이 있어 session 유지가 안될 수 있습니다.

 

이러한 문제를 해결하기 위해 Redis와 같은 메모리 기반 데이터베이스나 캐싱 솔루션 등을 활용하여 데이터베이스에 session을 관리하더라도 빠른 응답 속도를 유지할 수 있게 되었지만, 서버에서 상태를 저장하거나 관리하지 않아도 되는 JWT 기반 방식을 아래에서 소개해보도록 하겠습니다.

 


✔️ JWT 방식이란 ?

JWT란 JSON Wen Token으로, 말그대로 사용자에 관한 정보를 저장하는 JSON 포맷의 웹 토큰입니다.

출처 -  https://supertokens.com/blog/what-is-jwt

JWT는 Header, Payload, Signature의 세 부분으로 구성되어 있습니다.

 

1. Header : JWT의 유형 및 Signature를 해싱하기 위한 알고리즘을 포함합니다. 일반적으로 {"alg": "HS256", "typ": "JWT"}와 같이 해싱 알고리즘과 토큰 유형을 명시합니다.

 

2. Payload : 토큰에 포함될 클레임(Claim) 정보들을 담고 있습니다. (클레임은 사용자에 대한 정보와 추가적인 메타데이터를 JSON 형태로 포함합니다.) 클레임은 아래의 3가지 타입으로 나뉩니다.

 

2.1 Registered Claims (등록된 클레임) : 표준화된 클레임으로, 이미 정의된 종류의 데이터들로 토큰 정보를 나타내며, 선택적으로 사용할 수 있습니다. 이러한 클레임들은 JWT를 간결한 형태로 유지하기 위해 각 길이가 3인 문자열로 표현됩니다. 예를 들어 Issuer는 'iss', Subject는 'sub'와 같이 표현됩니다. 아래는 Registered Claim의 종류입니다.

  • - iss : 토큰 발급자(issuer)의 식별자를 나타냅니다.
  • - sub : 토큰의 제목(subject)을 나타내며, 이메일과 같이 특정 사용자를 식별하는 값을 사용합니다.
  • - aud : 토큰이 사용되는 대상(audience)을 나타냅니다.
  • - exp : 토큰의 만료 시간(expiration)을 나타냅니다. 이 시간 이후로는 토큰이 더 이상 유효하지 않습니다.
  • - nbf : 토큰의 활성화 시간(not before)을 나타냅니다. 이 시간 이전에는 토큰이 유효하지 않습니다.
  • - iat : 토큰이 발급된 시간(issued at)을 나타냅니다.
  • - jti : JWT의 고유 식별자(jwt id)로, 중복 사용을 방지하며 일회용 토큰(Access Token) 등에 사용됩니다.

 

2.2 Public Claims (공개 클레임) : 사용자 정의 클레임으로, 충돌을 방지하기 위해 https://www.iana.org/assignments/jwt/jwt.xhtml을 참고하거나 URI 형식으로 정의됩니다. 예를 들어, 프로필 정보나 사용자의 역할 등이 있습니다.

 

2.3 Private Claims (비공개 클레임): 사용자 정의 클레임으로, 클라이언트와 서버 사이에 협의된 정보를 저장합니다. 예를 들어, 특정 서비스에서 필요로 하는 추가 정보나 커스텀한 사용자 정보를 담을 수 있습니다.

{
	"user_id": 12345
	"account_type": "premium"
}

 

3. Signature : Header와 Payload를 각각 인코딩한 후, 서버에서 생성된 secret key를 사용하여 서명된 값입니다. 이 서명을 통해 토큰이 변경되었는지 여부를 확인할 수 있습니다.

 

https://jwt.io/#debugger-io

 

📝 JWT 기반의 인증 절차

그렇다면, session 기반과 달리 JWT 기반은 어떻게 사용자를 인증하는지 확인해 봅시다.

 

1. 로그인 시, 서버는 사용자 정보를 기반으로 JWT를 생성하여 사용자에게 전달합니다.

2. 사용자는 JWT를 저장하고, 요청 시에는 HTTP 헤더를 통해 서버에 JWT를 전송합니다.

3. 서버는 전송된 JWT를 확인하여 사용자의 신원을 확인할 수 있습니다.

 

이때, 토큰 자체에 필요한 정보가 포함되어 있으며 이 JWT는 서버 측에서 저장하지 않습니다. 결국 서버는 secret key만을 가지고 사용자에게 토큰만 부여하면, 매 요청마다 사용자가 제출한 토큰을 검증하기만 하면 됩니다. 이때 서버는 secret Key를 통해 서명을 확인하고, 페이로드를 통해 필요한 사용자 정보를 획득합니다.

 

위와 같은 특징을 봤을 때, JWT 기반 방식은 session과 다르게 사용자들의 상태를 저장할 필요없이 상대적으로 간편하게 사용자의 인증과 권한 부여를 관리할 수 있는 장점을 갖고 있습니다.

 

그러나, 토큰 자체에 필요한 정보가 모두 포함되어 있는 self-contained 특징은 토큰이 탈취되면 정보가 노출될 가능성이 있음을 말하기도 합니다. session 기반의 경우 서버가 사용자 정보를 관리하지만, JWT는 이미 발급한 토큰의 정보를 수정할 수 없습니다. 즉, 만일 만료되지 않은  토큰이 탈취되면 무효 처리를 해야하는데 이게 어렵다는 뜻입니다.

 

🤔 그럼 어떻게 해야하는가 🤔

이를 해결하기 위한 방법 중 가장 많이 사용되는 방법이 토큰을 두 개(Access Token, Refresh Token) 발급하는 방식입니다.

이는 아래 포스팅에서 자세히 다루도록 하겠습니다. ;)

 

https://jieeeuun.tistory.com/73

 

[Spring / JWT] Access Token과 Refresh Token

https://jieeeuun.tistory.com/72 [Spring] Session 기반과 JWT 기반의 인증 개인 프로젝트에서 인증 기능을 구현해야 하는데, 이때 SpringBoot에서 인증을 구현하는 주요 방식으로 Session 기반과 JWT(JSON Web Token) 기

jieeeuun.tistory.com


이렇게 Session 방식과 JWT 방식에는 각각 장단점이 존재합니다. 보안 요구사항이나 확장성, 개발 용이성 등을 종합적으로 고려하여 적절한 방식을 선택하는 것이 중요할 거 같습니다.


References