JWT란 무엇인가? with 쿠키,세션,토큰

JinYoung Choi·2023년 6월 5일
0

이번 메인 프로젝트에서 여러 가지 파트 중 회원가입과 로그인 파트도 맡게 되었다.

우리 프로젝트에선 JWT를 사용한 인증을 처리하려고 한다.

개발에 들어가기 전 JWT에 대해 자세히 공부하고 개발에 들어가 보려고 한다.

인증(Authentication)


사용자가 누구인지 확인하는 과정을 의미한다.
예를 들어, 사용자가 로그인 할 때, 아이디와 비밀번호를 통해 사용자가 실제로 그 계정의 소유자인지 확인하는 과정이 인증에 해당한다.
JWT는 이 인증 과정 이후에 사용자의 ID와 같은 정보를 포함하고 있어, 사용자가 자신의 신원을 서버에 계속적으로 증명할 수 있게 해준다.


웹에서 클라이언트의 인증을 확인하는 방식으로는 주로 쿠키, 세션, 토큰이라는 세 가지 방식이 사용된다.
이 세 가지 각각의 방식은 서로 다른 특징과 장단점을 갖고 있으며, 각 상황에 따라 적합한 방식이 다를 수 있다.

사용자 인증을 위해 JWT(JSON Web Token)라는 토큰 기반의 인증 방식을 배우기 전에, 우리는 먼저 쿠키와 세션에 대한 통신 방식, 그리고 이들이 갖는 각각의 특성과 장단점을 다시 한번 살펴볼 필요가 있다.

또한, 토큰 기반의 인증 방식을 왜 사용하는지에 대해서도 이해해야 한다. 쿠키와 세션에 비해 토큰 방식이 어떤 이점을 가지며, 어떤 상황에서 토큰 방식이 더 적합한 선택이 될 수 있는지에 대해 알아보는 것이 중요하다. 이를 통해 각 인증 방식의 적절한 활용법에 대해 이해할 수 있다.


쿠키????? 이건가??????

쿠키(Cookie)는 클라이언트 측에서 관리하는 작은 데이터 파일이다.

웹사이트를 방문할 때 웹 서버는 HTTP 응답 헤더를 통해 클라이언트에게 쿠키를 전달하게 된다.
이후 클라이언트는 웹 브라우저를 통해 이 쿠키를 저장하고, 같은 서버에 다시 요청을 보낼 때마다 이 쿠키를 HTTP 요청 헤더에 담아서 함께 보낸다.

쿠키를 이용해 인증을 처리하는 과정

  1. 사용자가 로그인을 시도합니다. 이때 사용자의 아이디와 비밀번호 정보가 서버로 전송된다.

  2. 서버는 받은 정보를 확인하여 사용자를 인증한다. 인증이 성공적으로 이루어지면, 서버는 사용자의 고유한 ID와 같은 정보를 쿠키에 담아 클라이언트에게 전송한다.

  3. 클라이언트는 전달받은 쿠키를 웹 브라우저에 저장한다.

  4. 클라이언트는 이후 서버로 요청을 보낼 때마다 이 쿠키를 함께 전송한다. 서버는 쿠키를 확인하고 사용자를 인증한다.

예시)

어떤 온라인 쇼핑몰에서 로그인을 한 뒤 상품을 장바구니에 담는다고 가정 해보자.
이때 웹 서버는 쿠키를 통해 사용자가 로그인된 상태를 유지할 수 있으며, 이 쿠키는 사용자가 장바구니에 상품을 추가하거나 삭제하는 등의 동작을 할 때마다 서버에 전송되어 사용자를 인증하게 된다.
이렇게 쿠키는 서버와 클라이언트 사이에서 상태를 유지하게 해주는 역할을 한다.

장점

  1. 클라이언트 측에서 관리: 쿠키는 클라이언트의 브라우저에 저장되므로, 서버 측에서 별도로 사용자 정보를 유지할 필요가 없다. 이는 서버의 리소스를 절약하는 데 도움이 된다.

  2. 사용자 경험 향상: 쿠키는 사용자의 웹사이트 방문 기록, 사용자 설정, 로그인 상태 등을 저장하므로 사용자 경험을 개선하는 데 도움이 된다.

단점

  1. 보안 취약: 쿠키 정보는 사용자의 컴퓨터에 저장되므로, 쿠키 정보가 노출되거나 변경될 위험이 있다.
    또한, 쿠키는 사용자의 컴퓨터와 웹 서버 사이를 왕래하며 전송되는데, 이 과정에서 쿠키 정보가 탈취당할 수 있다.

  2. 크기 제한: 쿠키는 일정 크기 이상의 정보를 저장할 수 없다.
    각 브라우저마다 다르지만, 일반적으로 하나의 도메인에 대해 20개, 그리고 하나의 쿠키에 대해 4KB의 정보만 저장할 수 있다.

  3. 사용자에 의한 삭제 가능성: 사용자가 쿠키를 직접 삭제하거나,
    브라우저 설정을 통해 쿠키를 차단할 수 있다. 이 경우, 웹사이트의 일부 기능이 제대로 동작하지 않을 수 있다.

Session

세션(Session)은 사용자가 웹사이트에 접속하는 시점부터 브라우저를 종료하여 접속을 종료하는 시점까지를 말한다.
쿠키와 같이 사용자를 식별하는데 사용되지만, 쿠키와는 달리 세션 데이터는 서버 측에 저장된다.

예시)

온라인 쇼핑몰에서 장바구니 기능을 생각해보자.
사용자가 상품을 장바구니에 담으면 그 정보는 세션에 저장된다.
이후 사용자가 다른 페이지로 이동하거나 브라우저를 닫았다가 다시 열어도 장바구니에 담긴 상품이 그대로 유지되는 이유는 서버 측에 저장된 세션 데이터 때문이다.

사용자가 로그인하면, 사용자의 아이디와 같은 정보가 세션에 저장되고, 서버는 그 세션을 식별하는 세션 ID를 브라우저에게 전달한다.
브라우저는 이후 요청마다 세션 ID를 함께 전송하여 자신을 식별한다.
서버는 세션 ID를 통해 해당 사용자의 세션 데이터를 찾아 사용자를 인증하고, 필요한 정보를 제공한다.

장점

  1. 보안성: 세션 정보는 서버 측에 저장되므로 쿠키보다 안전하다. 사용자는 세션 ID만 알 수 있고, 세션에 저장된 내용을 직접 볼 수는 없다.

  2. 데이터 용량 제한 없음: 세션은 서버에 저장되므로 쿠키와 달리 데이터 용량에 큰 제한이 없다.

단점

  1. 서버 자원 사용: 많은 사용자가 동시에 접속하게 되면 서버에 부하가 생길 수 있다.
    세션 정보를 모두 서버 메모리에 저장하면 메모리 부족이 생길 수 있다.

  2. 사용자 인식 문제: IP를 변경하거나 브라우저를 닫을 경우 세션 연결이 끊어질 수 있다.
    이 때문에 사용자가 로그인 상태를 유지하려면 다시 로그인 해야 할 수 있다.

Token

토큰(Token) 기반 인증은 사용자 인증에 있어서 쿠키나 세션을 사용하지 않는 방법이다.
이 방법은 토큰이라는 데이터 단위를 사용해서 사용자의 인증 정보나 권한을 포함한다.
이 토큰을 사용하여 사용자의 신원을 확인하고, 권한을 검사한다.

예시)

사용자가 웹사이트에 로그인하면 서버는 사용자의 정보와 권한을 담은 토큰을 생성한다.
이 토큰은 서버에 의해 암호화되어 사용자에게 전달된다.
사용자는 이 토큰을 저장하고, 이후 서버에 요청을 보낼 때마다 이 토큰을 같이 보낸다.

서버는 요청을 받을 때마다 전달받은 토큰을 검사하여 사용자를 식별하고, 권한을 확인한다.
토큰이 유효하면 요청을 처리하고, 그렇지 않으면 거부합니다.
예를 들어, 블로그 글 수정 요청이 들어왔을 때, 해당 글의 작성자와 토큰에 담긴 사용자 정보가 일치하는지 확인하고 일치할 경우에만 수정을 허용한다.

장점

  1. 상태 유지(Stateless) 구조: 토큰은 사용자의 상태를 서버에 저장하지 않는다.
    사용자의 모든 정보는 토큰 자체에 포함되기 때문에 서버는 사용자의 상태를 기억할 필요가 없다.
    이는 서버의 부하를 줄이고 확장성을 높이는데 도움이 된다.

  2. 크로스 도메인(Cross-Domain) 요청 가능: 쿠키는 같은 도메인에서만 사용할 수 있지만 토큰은 이런 제약이 없다. 따라서 다른 도메인으로 요청을 보낼 때 토큰을 이용하여 인증할 수 있다.

  3. 모바일 어플리케이션에 적합: 쿠키는 웹 브라우저에서 주로 사용되지만, 모바일 앱에서는 토큰이 더 적합하다.

단점

  1. 토큰 관리: 토큰이 만료되면 사용자는 다시 로그인해야 합니다. 또한, 토큰이 탈취되면 이를 이용해 악의적인 행동을 할 수 있다. 따라서 토큰의 관리와 보안이 중요하다.

  2. 데이터 용량: 토큰은 사용자의 모든 정보를 담고 있으므로 길이가 길어질 수 있다.
    이는 네트워크 부하를 증가시킬 수 있다.

⭐JWT란?⭐


JWT(Json Web Token)는 웹 표준(RFC 7519)으로 정의된 토큰이다.
사용자 인증에 필요한 정보를 JSON 형식으로 안전하게 전달하는데 사용된다.

이 JSON 웹 토큰은 클라이언트와 서버 간 정보를 교환할 때 필요한 데이터를 압축해서 안전하게 전송할 수 있도록 만들어졌다. 정보의 무결성을 확보하기 위해 디지털 서명이 사용되며, 필요에 따라 암호화할 수도 있다.

JWT의 구성

  • 헤더(Header)
  • 페이로드(Payload)
  • 서명(Signature)
xxxxx[Header].yyyyy[Payload].zzzzz[Signature]

발급 된 토큰 정보는 https://jwt.io/ 에서 확인할 수 있다.

JWT의 헤더(Header)는 두 가지 주요 정보를 담고 있다.

  • 타입(Type): 이는 토큰의 종류를 나타내는 부분으로, JWT를 사용하는 경우 'JWT'라고 명시된다.

  • 알고리즘(Algorithm): JWT를 서명하는 데 사용되는 암호화 알고리즘을 나타낸다. 주로 HS256 혹은 RS256이 사용되지만, 다른 알고리즘도 사용될 수 있다.

PAYLOAD

JWT의 페이로드(Payload)는 토큰 자체에 담기는 실제 데이터를 포함하고 있다.
페이로드는 클레임(Claim)들의 집합으로 구성되며, 클레임은 서버와 클라이언트 간에 주고받는 정보의 한 조각을 의미한다.

  • 등록된 (Registered) 클레임: 이는 JWT 스펙에서 사전 정의된 클레임들로, 선택적으로 사용할 수 있다.
    예를 들어 "iss" (발행자), "exp" (만료 시간), "sub" (주제), "aud" (대상), 등이 있다.

  • 공개 (Public) 클레임: 사용자가 임의로 정의할 수 있는 클레임이다.
    하지만 충돌을 피하기 위해 JWT에 등록된 이름을 사용하는 것이 좋다.

  • 비공개 (Private) 클레임: 특정 사용자와 서버간에 합의하에 사용되는 클레임이다.
    일반적으로 사용자의 ID나 이메일, 권한 등을 저장하는데 사용된다.

Signature

JWT의 서명(Signature) 부분은 헤더와 페이로드의 무결성을 보장하고, 토큰이 중간에 변경되지 않았음을 확인하는 역할을 한다.

헤더와 페이로드를 각각 Base64Url로 인코딩하고, 이 두 부분을 합친 후에 비밀 키(Secret Key)를 이용하여 지정된 해시 알고리즘(HS256, RS256 등)으로 해시를 생성한다.
이 과정을 통해 얻은 문자열이 서명이다.

이 서명은 토큰의 세 번째 부분을 구성하며, 토큰 전체를 '.'으로 구분된 세 부분으로 나눈다.
이 서명이 있기 때문에 토큰이 전송 과정에서 변조되었는지를 검증할 수 있다.
서버는 헤더와 페이로드를 다시 합친 후, 동일한 비밀 키와 해시 알고리즘을 이용해 해시를 다시 생성하고, 이를 받은 토큰의 서명과 비교한다.
만약 서명이 일치하지 않는다면, 토큰이 변조되었음을 의미하며, 이런 토큰은 거절된다.

따라서, 이 서명 부분은 JWT가 안전하게 데이터를 전달할 수 있게 하는 핵심적인 부분이다.
하지만 비밀 키는 매우 중요하므로, 비밀 키가 유출되지 않도록 주의해야 한다.
비밀 키가 유출되면 외부에서 임의로 토큰을 생성하거나 변조할 수 있게 된다.

JWT 예시

사용자가 웹사이트에 로그인하면 서버는 사용자의 정보를 JWT 토큰으로 만들어서 사용자에게 전달한다.
이 JWT 토큰은 클라이언트(브라우저)에서 관리되고, 사용자가 서버에 요청을 보낼 때마다 이 토큰을 함께 보낸다.

서버는 요청을 받을 때마다 전달받은 JWT 토큰을 검증한다.
만약 토큰이 변조되거나 만료되었으면 요청을 거부하고, 그렇지 않으면 요청을 처리한다.

장점

  • 상태 유지가 필요 없음: JWT는 상태 유지가 필요 없는 Stateless 토큰이므로, 서버에 부하를 주지 않고 확장성을 높일 수 있다.

  • Self-contained: JWT는 필요한 모든 정보를 자체적으로 가지고 있다.
    따라서 토큰이 전달되는 과정에서 다른 곳에 따로 데이터를 저장할 필요가 없다.

  • 크로스 도메인 요청 가능: 쿠키와 같은 제약이 없으므로 다른 도메인간에도 요청을 보낼 수 있다.

단점

  • 토큰의 길이: JWT는 필요한 모든 정보를 포함하고 있으므로 길이가 길어질 수 있다.
    이는 데이터를 주고 받는 과정에서 성능에 영향을 줄 수 있다.

  • 서버에서 토큰을 취소할 수 없음: JWT는 만료 시간이 지나기 전까지는 유효한 것으로 간주된다.
    따라서 서버에서 토큰을 취소하는 것이 불가능하므로, 토큰이 탈취 당했을 때 이를 막을 수 있는 방법이 제한적이다.

JWT와 세션 비교와 사용 방법

JWT는 사용자의 인증 정보를 토큰 형태로 클라이언트에게 전달하여 사용하는 방식이다.
이 방식은 Stateless(무상태)라고 불리는데, 그 이유는 JWT를 사용하면 서버는 사용자의 상태를 유지하거나 기억하지 않아도 되기 때문이다.
사용자가 요청을 보낼 때마다 토큰을 함께 보내고, 이 토큰에는 필요한 모든 정보가 들어 있다.

하지만 이러한 Stateless 특성 때문에 세션을 완전히 대체하진 못한다.
세션을 사용하면 사용자의 상태를 서버에서 관리할 수 있기 때문에, 보다 세밀한 제어가 가능하다.
예를 들어, 특정 기기에서만 로그인이 가능하도록 제어하거나, 한 번에 여러 기기에서 로그인이 불가능하도록 제어하는 것이 가능하다.

반면에 JWT는 한 번 발급되면 그 토큰의 유효기간이 끝날 때까지 유효하며, 서버는 이미 발급된 토큰에 대해 제어할 방법이 없다.
따라서, 만약 JWT가 노출되거나 도난당했을 경우, 해당 토큰을 즉시 무효화하는 것이 어렵다.

이러한 문제를 해결하기 위해 일반적으로는 accessToken과 refreshToken 두 가지 종류의 토큰을 사용한다. accessToken은 짧은 유효기간을 가지고 있어 인증을 위해 사용되며, refreshToken은 accessToken이 만료됐을 때 새 accessToken을 발급받기 위해 사용된다.
refreshToken의 유효기간은 일반적으로 accessToken보다 길게 설정된다.

이렇게 하면, 만약 사용자를 로그아웃시키거나 토큰을 무효화하고 싶을 경우, 서버에서 해당 사용자의 refreshToken을 제거함으로써 accessToken을 재발급받는 것을 막을 수 있다.
하지만 여전히 accessToken의 유효기간 동안은 토큰을 완전히 무효화하는 것이 불가능하다.

따라서, JWT는 세션의 대체제로 사용될 수 있지만, 상황에 따라 세션과 JWT를 적절히 조합해서 사용하는 것이 중요하다.

profile
백엔드 취준생

0개의 댓글