[Server] 쿠키&세션&토큰 에 대해 알아봅시다.

최동근·2022년 12월 23일
0

web

목록 보기
1/1
post-thumbnail

안녕하세요 서버는 클라이언트를 인증하는 방식으로 3가지 방식을 사용할 수 있습니다.
오늘 소개할 3가지는 쿠키,세션 그리고 토큰 입니다.

이번 포스팅에서는 각 인증 방식의 특징과 장단점을 알아보겠습니다 🔥

👮‍♀️ 웹의 개인화

현대인들에게 없어서는 안될 webHTTP 프로토콜 이라는 규약을 통해 작동합니다.
클라이언트는 서버에게 Request 를 보내고, 서버는 해당 Request 를 처리 후 적절한 Response 를 생성하여 보냅니다.

이때 Http 통신ConnectionlesStateless 특성을 가지고 작동합니다 🏋️

Connectionless

Http 통신 을 하기 위해서는 클라이언트와 서버가 연결이 되어있어야 합니다.
이 커넥션을 유지하는 것 자체도 부담이 되며, 수 없이 많은 클라이언트가 동시에 서버에 요청을 하는 경우 그 만큼 많은 커넥션을 생성합니다.
이는 서버 입장에서 큰 부담이 되며 부하가 될 수 있는데 이를 해결하기 위해 Http 프로토콜 위에서 동작하는 Http 통신 은 통신을 한번 할 때 클라이언트와 서버를 연결하고, 통신이 끝나면 바로 연결을 끊습니다 ✂️
이를 통해 서버 자원을 효율적으로 관리하고 가능한 여러 클라이언트의 요청에 응답합니다.

이렇게 한 클라이언트가 여러번의 요청을 보내도 커넥션이 계속 끊어졌다, 연결됐다를 반복하는 특성을 Connectionless 라고 합니다.

Connectionless 장점 & 단점

  • 장점
    [1] 서버의 자원을 좀 더 효율적으로 사용 가능하며 더 많은 요청을 처리할 수 있습니다.

  • 단점
    [2] 한번 맺어진 커넥션은 유지되지 않기 때문에 요청마다 매번 커넥션을 만들어주어야 합니다.

Stateless

Stateless 특성은 Http 통신 이 이전 요청의 상태를 기록하지 않기 때문에 서버가 클라이언트를 식별할 수 없는 특성을 말합니다.
Connectionless 특성 때문에 생겨나며, 한번의 요청 후 커넥션이 유지 되지 않기 때문에 다음 요청시 서버는 클라이언트를 식별하지 못합니다.
즉, 이번 요청이 어떻게 끝났느냐에 따라 다음 요청이 영향을 받지 않고 모든 요청이 독립적입니다.
만약 다음 요청이 이전 요청과 관련된 요청이면 서버는 이전 요청을 기억하지 못하기에 한번의 요청에 이전 요청 내용까지 모두 전달해야합니다.

Stateless 에 반대되는 특성은 Stateful 이며 이는 이전 상태를 보존하며 이전 요청의 내용을 기억하며 다음 요청에 반영할 수 있습니다.

Stateless 장점 & 단점

  • 장점
    [1] 이전 요청을 기억할 필요가 없기에, 이를 위한 저장 공간이 필요없습니다.
    [2] 서버의 디자인이 단순합니다.
    [3] 서버가 여러대의 컴퓨터로 구성되는 경우, 어떠한 서버 컴퓨터가 요청을 받더라도 응답이 가능합니다.


  • 단점
    [1] 클라이언트를 식별하기 어렵습니다.
    [2] 매 요청마다 추가 정보(이전 요청에 대한 정보)가 필요합니다.

웹의 개인화 는 웹의 발전으로 인해 생겨났으며 클라이언트에 맞게 개인화된 웹 사이트를 제공하는 웹의 특성을 말합니다.
예를 들어 특정 클라이언트가 신규 회원인 경우, 환영 메세지를 보낸다거나, 특정 브랜드를 많이 검색한 클라이언트에게 해당 브랜드의 신발을 추천 정보로 보여주는 등 서버는 클라이언트의 상황에 맞는 응답을 서버는 제공해야하는 필요성이 생겨났습니다.

웹의 개인화 는 결국 특정 클라이언트에 맞는 데이터(정보) 를 서버에서 제공해야하기에 클라이언트를 식별를 요구합니다.
하지만 기존 Http 통신 은 Connectionless, Stateless 특성을 가지기에 클라이언를 식별할 수 없습니다.
이러한 한계를 극복 및 웹의 보안을 위해 생겨난 것이 쿠키(Cookie) 방식입니다 🔥

👮‍♀️ 쿠키(Cookie)

첫번째로 알아볼 인증 방식은 쿠키(Cookie)입니다 🍪
쿠키는 Key-Value 형식의 문자열 덩어리 입니다.
클라이언트가 어떠한 웹 사이트를 방문할 경우, 그 사이트가 사용하고 있는 서버를 통해 클라이언트의 브라우저에 설치되는 작은 기록 정보 파일입니다.
쿠키의 가장 두드러지는 특징은 사용자 관련 정보를 브라우저가 관리한다는 것입니다 👨‍🔧

쿠키의 인증 방식

1. 클라이언트의 첫 Http Request

  • 클라이언트가 웹 사이트를 첫 방문하면 서버는 해당 클라이언트를 식별하기 위한 Key-Value 객체를 만듭니다.

2. 서버의 Http Response

  • Http 헤더의 Set-Cookie 항목에 쿠키를 담아서 전달합니다. 클라이언트는 Set-Cookie 헤더에 있는 쿠키를 브라우저에 저장합니다.
  • 브라우저에서 쿠키의 저장 위치는 브라우저가 어떻게 쿠키 스토리지를 구현했느냐에 따라 다릅니다.

3. 클라이언트의 Http Request + Cookie

  • 브라우저에 쿠키를 저장했으면 다음의 Request 에는 Http 헤더에 쿠키를 포함합니다.
  • 브라우저는 수백개의 쿠키를 가지는데, 모든 사이트를 방분하거나 API 요청을 보낼 때마다 몇백개의 쿠키를 Http 헤더에 담지는 않습니다.(쿠키의 Domain 속성과 Path 속성을 사용)

4. 서버의 클라이언트 식별

  • 클라이언트의 요청으로 부터 받은 Cookie 를 통해 서버는 클라이언트를 식별할 수 있습니다. (Stateful 특성)

쿠키의 종류

2가지 종류의 쿠키가 있으며, 둘의 차이점은 쿠키의 파기 시점 입니다.

1. 세션 쿠키

만료일을 설정하지 않았기 때문에 브라우저를 종료하면 파기됩니다.
사용자가 특정 사이트를 탐색할 때 선호 사항, 임시 설정 등을 저장하는 쿠키

ex) 최근 본 상품, 최근 검색어

2. 지속 쿠키

디스크에 저장되어서 만료일까지는 브라우저를 끄거나 재부팅하여도 남아있습니다.
다음 방문에도 유지돠는 설정 정보나 로그인 정보등을 저장하는 쿠키

ex) 일주일간 팝업 보지 않기, 로그인 유지

쿠키의 한계

쿠키의 방식에 대해서 알아보았습니다.
하지만 쿠키는 다양한 한계점이 존재합니다.

    1. 쿠키의 용량의 제한이 있습니다.
    1. 요청마다 헤더에 쿠키가 포함되기 때문에 보안의 문제가 발생할 수 있습니다.(중요한 정보 x)
    1. 브라우저마다 저장되는 쿠키가 다르기 때문에 브라우저끼리 공유가 불가능합니다.

이러한 단점을 보완해주는 것이 세션 입니다.

👮‍♀️ 세션(Session)

여기서 세션방식은 보통 쿠키와 함께 작용됩니다.
세션의 인증 방식부터 알아보겠습니다 🏋️

세션의 인증 방식

1. 클라이언트의 첫 Http Request

  • 클라이언트가 웹 사이트를 첫 방문하면 세션이 생성 후 서버 메모리(혹은 데이터베이스) 상에 저장됩니다.
    세션은 Key-Value 형식으로 생성됩니다.
  • 또한 세션을 구분하기 위헤 세션 Id 를 생성합니다. (Key : 세션 Id, Value : 세션)

2. 서버의 Http Response

  • 서버는 생성한 세션 Id 를 브라우저에 쿠키에 저장합니다.

3. 클라이언트의 Http Request

  • 클라이언트는 해당 사이트에 대한 모든 Request 에 Session Id 를 쿠키에 담아 전송합니다.

4. 서버의 클라이언트 식별

  • 서버는 클라이언트의 Request 쿠키에 담겨있는 세션 Id 를 통해 서버의 저장되어 있는 세션 Id 와 비교해서 인증을 수행합니다.

세션의 특징

앞에서 세션의 인증 방식에서 살펴본 바와 같이 세션은 클라이언트의 인증 정보와 관련된 민감한 정보를 서버에서 관리합니다.
서버는 클라이언트의 로컬 컴퓨터보다 강한 보안 기술이 구현되어 있기에 악의적인 보안 공격에 안전합니다.

세션의 한계

세션은 쿠키의 취약한 보안성을 보완하기 위해 만들어진 기술이지만
역시나 한계가 존재합니다.

    1. 서버가 클라이언트의 정보를 관리하기 때문에 서버의 메모리 공간을 차지합니다.
      이는 서버의 부하가 될 수 있습니다.
    1. 클라이언트의 Request 로부터 받은 세션 Id 를 통해 자신의 메모리 혹은 데이터베이스에 있는 세션을 조회해야합니다. 즉, 오버헤드가 발생합니다.
    1. 가령 해당 서버에 동시 접속자가 많은 경우 서버의 과부하가 발생할 수 있습니다.
    1. 세션 역시나 보안 측면에서 허점이 존재하는데 쿠키(내부에 세션 Id 존재)를 탈취해서 서버에 요청을 보내면 정보가 유출될 수 있습니다.
    1. 서버가 다중 서버인 경우 매번 같은 서버 컴퓨터로 Request 가는 것을 보장할 수 없으며 다중 서버 환경에서 서버 컴퓨터가 개별적인 Session 저장소를 가질 경우 Session ID 가 저장되지 않은 곳으로 요청이 가면 사용자를 식별할 수 없습니다. 물론 이에 대해서 Load Balancer 등의 해결방법이 있습니다. 하지만 이러한 해결방법은 복잡한 로직을 요구합니다.

이처럼 세션에도 한계점이 존재하기에 토큰(Token) 을 이용한 인증 방식이 탄생합니다.

👮‍♀️ 토큰(Token)

여기서 토큰 이란 인증에 필요한 정보를 암호화시킨 것입니다.
이번 포스팅에서는 가장 대중화된 토큰인 JWT 를 알아보겠습니다 🔥

본격적으로 토큰 기반 인증 시스템을 알아보기 전에 인증(Authentication)인가(Authorization) 을 알아보겠습니다.

인증과 인가

인증(Authentication) 은 사용자의 신원을 검증하는 프로세스를 뜻합니다.

앞에서도 알아보았듯이 웹은 Http 프로토콜 기반으로 동작합니다.
따라서 Connectionless, Stateless 한 특성을 가지는데 이러한 특성은 모든 요청마다 인증 을 요구합니다.
매번 로그인을 한다는 것은 클라이언트에게 매우 번거로운 작업이 될 수 있습니다.
이러한 작업을 막기위해 Cookie, Session 그리고 Token 을 사용하는 것입니다.

인가(Athorization) 은 사용자가 어떠한 자원에 접근할 수 있는지를 확인하는 절차입니다.

인가는 인증 이후의 프로세스입니다.
가령 특정 웹 사이트의 관리자 기능은 아무 클라이언트에게 접근하는 것을 허용하면 안됩니다.
즉 관리자에게만 해당 기능을 제공해야하는데 이러한 것을 인가 라고 합니다.

토큰의 인증 방식

해당 이미지는 토큰을 이용한 인증 방식을 도식화한 이미지입니다 😛

1. 클라이언트의 첫 Http Request

  • 클라이언트가 첫 Request를 보낼 때 서버는 클라이언트의 인증 정보(아이디,비밀번호)를 이용하여 암호화된 토큰을 생성합니다. 토큰 생성에는 다양한 방식이 존재합니다.

2. 서버의 Http Response

  • 서버는 클라이언트로부터 받은 인증 정보가 유효한지 확인하고, 토큰을 Http Response 에 담아서 전달합니다.
  • 이때 해당 토큰은 서버의 Secret Key 로 암호화 되어 있기 때문에 탈취해도 복호화할 수가 없습니다.
  • 토큰 기반 인증 방식에는 비대칭키 가 사용됩니다.

3. 클라이언트의 Http Request

  • 클라이언트는 서버로부터 발급받은 토큰을 클라이언트의 쿠키나 스토리지에 저장하고 , 서버에 Request 를 할때마다 해당 토큰을 Http Request 헤더에 포함시켜 보냅니다.

4. 서버의 클라이언트 인증

  • 서버는 클라이언트로부터 전달받은 토큰을 통해 클라이언트의 인증 과정을 수행합니다.
  • 토큰 자체에 클라이언트의 정보가 담겨져있기에 서버는 DB 를 조회하는 과정없이 인증 가능합니다.

JWT(Json Web Token) 이란

JWT 토큰 이란 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미합니다.
즉 토큰 구현 방법중 하나입니다.
JWT 는 JSON 데이터를 Base 64 URL-safe Encode 를 통해 인코딩하여 직렬화한 것이며, 토큰 내부에는 위변조 방지를 위해 개인키를 통한 전자서명이 들어있습니다.

JWT 구조


해당 이미지에서 알 수 있듯이 JWT 는 3가지 파트로 나뉩니다.

  • Header

    JWT Header 에는 토큰의 타입토큰의 해시 알고리즘 유형 정보가 들어갑니다.

    • 토큰의 타입(type) : JWT
    • 토큰의 해시 알고리즘(algorithms) : HS256
  • Payload

    JWT Payload 에는 토큰에서 실질적으로 사용될 정보인 클레임(Claim)이 들어 있습니다.
    클레임은 다시 3가지 종류로 나뉩니다.

    - Register Claim : 등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들입니다. 모두 선택적으로 작성이 가능합니다.
    Key 값은 간결함을 위해 모두 길이 3의 String입니다.

    iss : 토큰 발행자(Issuer)
     sub : 토큰 제목(Subject) 일반적으로 사용자의 이메일을 사용
     exp : 토큰 만료 시간(Expiration) 
     lat : 토큰 발급 시간(Issued At)
     jti : JWT 식별자(JWT ID) (중복 방지를 위해 사용)
     aud : 토큰 대상자(Audience)
     nbf : 토큰 활설 날짜(Not Before)

    - Public Claim : 공개 클레임은 사용자 정의 클레임으로 공개용 정보를 위해 사용됩니다. 충돌 방지를 위해 URI 포맷을 이용합니다.

    { "https://naver.com" : true }

    - Private Claim : 비공개 클레임은 사용자 정의 클레임으로 서버와 클라이언트 사이에 임의로 지정한 정보를 저장합니다.

    { "token_type" : access }

  • Signature

    서명이라고 불리며 앞에서 살펴본 HeaderPayload 값을 Base 64 URL-safe Encode 를 통해 인코딩하고, 인코딩한 값과 서버가 가지는 유일한 Secret Key 를 합쳐 Header 에서 정의한 해시 알고리즘으로 암호화를 합니다.

해당 이미지는 JWT 에 구성요소를 한눈에 이해하기 위한 이미지입니다 🔥
HeaderPayload 는 단순히 인코딩된 값이기 때문에 외부에서 복호화 및 조작이 가능하지만
Sigature 는 서버측에서 관리하는 Secret Key 가 유출되지 않는 이상 복호화할 수 없습니다 🚫

JWT 의 신뢰성

이렇게 생성된 JWT 는 클라이언트의 스토리지 혹은 쿠키 등의 저장이 됩니다.
이후 Request Authorization 헤더에 JWT 를 담아 요청을 보냅니다.
그렇다면 서버는 어떻게 서버의 오버헤드 없이 JWT 만을 복호화해서 인증과정을 수행할까요? 🤔
이 질문에 대한 답을 찾기 전 기억해야할 점은 JWT의 Header 와 Payload 는 단순히 인코딩되어 있기 때문에 충분히 위변조가 가능하다는 점입니다 ❗️

사실 JWT 의 본래 목적은 정보 보호 가 아닌 위조 방지 입니다 ❗️
예를 들어 JWT Payload의 특정 부분이 수정되었다고 가정해봅시다.
이렇게 수정된 JWT 를 Request로 받은 서버는 JWT의 Header 와 Payload 를 이용해서 Signature를 다시 생성해봅니다.
만약 앞에서 가정한것처럼 Payload의 특정 부분이 수정되었다면 Signature 값이 JWT 의 Signature와 다르겠죠?
이렇게 대조 결과가 일치하지 않는 경우 유저의 정보가 임의로 조작되었다는 뜻이므로 해당 자원에 대한 인증/인가가 불가능합니다 🚫

JWT 의 장점과 단점

  • 장점

    1) Header와 Payload 를 가지고 Signature 를 생성하므로 데이터 위변조를 방지할 수 있습니다.
    2) 세션과 달리 서버의 별도의 저장소가 필요없습니다.
    3) JWT 는 토큰에 대한 기본 정보와 전달할 정보 및 토큰이 검증됬음을 증명하는 서명 등 필요한 모든 정보를 자체적으로 가지고 있습니다.
    4) 세션과 달리 무상태(Stateless)가 되어 서버의 확장성이 우수합니다.
    5) Oauth 등과 함께 이용하기에 적절합니다.
    6) 모바일 환경에서는 쿠키, 세션같은 인증 방식이 존재하지 않으며 오로지 토큰을 이용해서 인증을 합니다.
    7) JWT 자체가 인증된 상태라는 것을 증명하는 것임으로 세션처럼 따로 DB 를 조회하는 오버헤드가 없습니다.

  • 단점

    1) 토큰 자체에 정보를 담고 있으므로 보안적인 측면에서 오히려 양날의 검이 될 수 있습니다.
    2) Payload에 3종류의 Claim(Register,Public,Private) 를 저장하기 때문에 정보가 많을수록 토큰의 길이가 늘어나고 네트워크에 부하가 될 수 있습니다.
    3) Payload 는 암호화된것이 아니라 인코딩되었기 때문에 중요한 정보가 실수로 포함되면 데이터 유출이 발생할 수 있습니다.
    4) 토큰은 클라이언트쪽에서 저장되기 때문에 혹여나 토큰 자체가 탈취되면 대처하기가 어렵습니다.

Access Token 과 Refresh Token

앞에서도 살펴 보았듯이 JWT에도 허점이 존재합니다. 예를 들어 JWT가 탈취당하면 대처하기가 매우 어렵습니다. 이를 해결하기 위해 현업에서는 Access TokenRefresh Token 을 사용하는 이중 인증 방식을 사용합니다 👨‍💻
간단하게 설명하면 Access Token 의 만료기간을 짧게 설정하는 것입니다.
그러면 클라이언트는 짧은 시간의 주기마다 다시 인증과정을 거쳐야하는 번거로움이 있습니다. 이때 Refresh Token 을 사용하여 새로운 Access Token 을 발급받습니다 ❗️

  • Access Token : 클라이언트가 갖고있는 실제로 유저의 정보가 담긴 토큰으로, 클라이언트에서 요청이 오면 서버에서 해당 토큰이 있는 정보를 활용하여 응답 생성(앞에서 살펴본 JWT)

  • Refresh Token : 새로운 Access Token을 발급해주기 위한 토큰입니다. 즉 Access Token의 재발급에 관여하는 토큰입니다.

Access TokenRefresh Token 의 원리에 대해 살펴보겠습니다 👨‍💻

[1] 클라이언트는 로그인을 하고 로그인에 성공했을 경우 서버는 클라이언트에게 Access TokenRefresh Token 을 발급합니다.

[2] 서버는 서버 스토리지에 Refresh Token 을 저장하고 클라이언트는 Access TokenRefresh Token 을 쿠키, 세션 혹은 스토리지에 저장하고 Request가 있을 때마다 두개의 토큰을 헤더에 담아서 보냅니다.

[3] 클라이언트는 추후 Request 마다 Refresh TokenAccess Token 을 같이 보냅니다.
서버는 위변조 검사와 함께 받은 Access Token 의 만료기간을 확인합니다.

[4] 만약 Access Token 의 만료 기간이 끝났을 경우, 서버는 자신의 스토리지에 있는 Refresh Token 과 비교해서 클라이언트가 보낸 Refresh Token 과 비교해서 일치하면 새로운 Access Token 을 발급해줍니다.

[5] 클라이언트가 로그아웃 하는 경우 서버는 Refresh Token 을 삭제합니다. 또한 Refresh Token 의 만료기간이 지난 경우 클라이언트는 비로소 다시 인증 과정을 거쳐야합니다.

보통 Refresh Token 의 만료기간은 Access Token 의 만료기간보다 긴 2주로 설정합니다 👮‍♀️


참고

HTTP의 특성과 쿠키, 세션, 토큰
Access Token + Refresh Token Authentication
[web] JWT 토큰 인증 이란?
Access Token & Refresh Token 원리

profile
비즈니스가치를추구하는개발자

0개의 댓글