# 쿠키(Cookie)와 세션(Session)

## HTTP 프로토콜 특징

* `클라이언트 서버 구조`
  * 클라이언트가 서버에 요청(request)을 보내면, 서버는 그에 대한 응답(response)를 보냄
* `비연결 지향(Connectionless)`
  * 클라이언트의 요청에 응답한 후에는 연결을 끊음(연결 유지 X)
  * 최소한의 자원으로 서버 유지
* `무상태(Stateless)`
  * 연결을 끊는 순간 클라이언트와 서버의 통신이 끝나고, 서버는 클라이언트의 상태 정보를 보존하지 않음
  * 클라이언트가 요청할 때 필요한 데이터를 추가적으로 담아서 전송해야 함
    * 항상 같은 서버를 유지하지 않아도 됨
    * 응답 서버를 쉽게 바꿀 수 있어서 서버 확장성이 높음(무한한 서버 증설 가능)

**쿠키와 세션의 필요성**

* HTTP 프로토콜의 특징으로 모든 요청 간에는 의존관계가 없음
  * 현재 접속한 사용자가 이전에 접속했던 사용자와 같은 사용자인지 아닌지 알 수 있는 방법 존재 X
* 통신할 때마다 새로 연결하기 때문에 클라이언트는 매 요청마다 인증을 해야 함
  * 로그인을 진행한 후, 다른 서비스를 사용하기 위해 매번 로그인(인증)을 하는 상황 발생
* 클라이언트의 상태 정보를 유지할 필요가 있을 경우, `쿠키`와 `세션`을 활용해서 Stateful한 동작 구현 가능
  * 무상태를 지향하기 위해 매 요청마다 필요한 정보를 담아 서버와 통신하는 경우, 비용과 부하가 커질 수 있음

\


## 쿠키(Cookie)

* 개념
  * 클라이언트 로컬에 저장되는 키와 값이 들어있는 파일
  * 사용자 인증이 유효한 시간 명시 가능(유효시간이 정해지면 브라우저가 종료되어도 인증 유지)
  * 클라이언트의 상태 정보를 브라우저(로컬)에 저장하여 참조
* 구성 요소
  * 쿠키의 이름(name)
  * 쿠키의 값(value)
  * 쿠키의 유효시간(Expires)
  * 쿠키를 전송할 도메인 이름(Domain)
  * 쿠키를 전송할 요청 경로(Path)
* 동작 방식
  1. 웹브라우저가 서버에 요청
  2. 상태를 유지하고 싶은 값을 쿠키(cookie)로 생성
  3. 서버가 응답할 때 HTTP 헤더(Set-Cookie)에 쿠키를 포함해서 전송
  4. 전달받은 쿠키는 웹 브라우저가 관리, 다음 요청 때 쿠키를 HTTP 헤더에 자동으로 넣어서 전송
  5. 서버에서 쿠키 정보를 읽어 이전 상태 정보를 확인 후 응답
* 사용 예
  * 아이디, 비밀번호 저장
  * 쇼핑몰 장바구니

\


## 세션(Session)

* 개념
  * 일정 시간 동안 같은 브라우저로부터 들어오는 요청을 하나의 상태로 보고 그 상태를 유지함
    * 웹 브라우저를 통해 서버에 접속한 이후부터 브라우저를 종료할 때까지 유지되는 상태
  * `쿠키`를 사용하여 값을 주고 받으며 클라이언트의 상태 정보를 유지함
    * 사용자 정보 파일을 쿠키는 브라우저에 저장하고, 세션은 서버측에서 관리
  * 사용자에 대한 정보를 서버에 두기 때문에, 사용자가 많아질수록 서버 메모리 많이 차지
  * 보안 면에서 쿠키보다 우수
    * 쿠키는 클라이언트 측에서 쉽게 탈취 가능
      * 쿠키는 클라이언트 측에서 변경이 가능한 반면, 세션은 서버에서만 변경 가능
    * 세션ID값 탈취는 적극적인 해킹공격으로 쿠키보다 어려움
* 동작 방식
  1. 웹브라우저가 서버에 요청
  2. 서버가 해당 웹브라우저(클라이언트)에 유일한 ID(Session ID)를 부여함
  3. 서버가 응답할 때 HTTP 헤더(Set-Cookie)에 Session ID를 포함해서 전송
  4. 웹브라우저는 부여된 Session ID를 쿠키에 저장해두고, 다음 요청 때마다 해당 쿠키를 HTTP 헤더에 넣어서 전송
  5. 서버는 Session ID를 확인하고, 해당 세션에 관련된 정보를 확인한 후 응답
     * 로그인을 하는 경우, 해당 Session ID의 로그인 상태를 유효한 값으로 바꿔 저장
     * 이후 요청에서 해당 Session ID를 가진 클라이언트는 로그인 상태가 유효하므로 별도의 로그인 없이 서비스 이용 가능
* 사용 예
  * 로그인

\


**다중 서버 환경에서 세션 관리**

서버를 다중화했을 경우, 세션 불일치 이슈 발생

* Sticky Session (스티키 세션)
  * 클라이언트의 요청이 항상 해당 클라이언트의 세션이 저장된 서버로만 전달됨
    * 로드밸런서에서 요청 쿠키(Session ID)를 읽고 지정된 서버(세션이 있는)로만 요청을 전달함
    * 세션 정보가 없을 경우, 로드밸런서의 기본 알고리즘대로 요청 전달
* Session Clustering (세션 클러스터링)
  * 클러스터링: 병렬 처리해서 여러 대의 서버를 하나의 서버처럼 운영
  * 세션을 서버 각각에 복사해서 모든 서버가 모든 세션을 보유하고 있음
  * 특정 서버에서 세션이 생성될 때 다른 서버로 세션을 전파하여 복제
* Session Storage (세션 스토리지)
  * 세션만 관리하는 별도의 DB 서버를 두고, 모든 서버가 해당 서버를 참조함

\


**토근 기반 인증 방식**

* 세션은 사용자의 수 만큼 서버 메모리를 차지하기 때문에, 최근에는 이를 보완하는 토근 기반의 인증방식을 많이 사용함(`stateless`)
* ex) `JWT(JSON Web Token)`

\


### 쿠키와 세션의 차이

|       |                쿠키                |                        세션                       |
| ----- | :------------------------------: | :---------------------------------------------: |
| 저장 위치 | 클라이언트의 웹 브라우저가 지정하는 메모리 or 하드디스크 |                      서버 메모리                     |
| 저장 형식 |               Text               |                      Object                     |
| 만료 시점 |            쿠키 저장 시 설정            |                  정확한 시점 알 수 없음                  |
| 보안    |          클라이언트에 저장되므로 취약         | Session ID만 저장하고, 이 값에 따라 서버에서 처리하므로 비교적 보안성 좋음 |
| 속도    |      클라이언트에 저장되어 서버에 요청 시 빠름     |        정보가 서버에 저장되어 있어 서버 처리가 필요해 쿠키보다 느림       |
| 용량 제한 |      한 도메인 당 20개, 한 쿠키당 4KB      |                       제한없음                      |

\
\


## ➕ 토큰

* 개념
  * 메모리 공간을 많이 차지하는 세션 방식의 대안으로 사용자에게 `세션 아이디` 대신 `토큰`을 발급

\


* 동작 방식
  1. 클라이언트가 서버에 접속 시, 서버는 클라이언트에게 인증되었다는 의미로 `토큰` 부여 (해당 토큰은 유일함)
     * 클라이언트는 전달받은 토큰을 쿠키나 스토리지에 저장함
  2. 토큰을 발급받은 클라이언트는 다시 서버에 요청을 보낼 때 헤더에 토큰을 심어보냄
  3. 서버의 토큰 일치여부 체크로 인증과정 처리
     * 클라이언트로부터 받은 토큰과 서버에서 제공한 토큰의 일치여부 체크

\


* 특징
  * 적은 서버의 부담
    * 토큰은 클라이언트에 저장 됨 → 세션을 관리했던 서버의 부담을 덜 수 있음
    * 해당 서버만이 만들 수 있는 토큰 발급 → 상태를 저장하지 않고도 사용자의 정보 파악 가능

\


* 한계
  * 한 번 발행한 토큰은 유효기간 만료시 까지 통제 불가
    * 여러 기기에서 로그인 제한 불가
    * 세션에 비해 토큰 정보 탈취 당할 가능성 높음
      * 해결 방법으로 `만료 시간` 이용
  * 토큰 자체 데이터 길이가 긺
    * 인증 요청이 많아질 수록 네트워크 부하가 심해짐

\
\


### JWT (JSON Web Token)

* 개념
  * 인증에 필요한 정보들을 `암호화`시킨 JSON 토큰
  * JWT토큰을 HTTP 헤더에 실어 서버가 클라이언트를 식별하는 방식

\


* 특징
  * JWT는 JSON 데이터를 Base64 URL-safe\_Encode를 통해 인코딩을 직렬화한 것
  * `Self-contained`
    * 필요한 정보를 자체적으로 지니고 있음
  * `Signature`
    * 전자서명을 통한 위변조 체크
    * 토큰 내부에 위변조 방지를 위해 개인키를 통한 전자서명이 들어감
      * 사용자가 JWT를 서버로 전송시 서버는 서명을 검정하는 과정을 거침
      * 검증 완료 시 요청한 응답을 돌려줌
  * `Calim`
    * JSON 데이터 구조로 표현한 토큰
    * 표준규약(RFC-7519)에 따라 생성된 암호화된 문자열(토큰)
  * `URL-safe`
    * 두 개체 사이에서 손쉽게 전달되며, 사용되는 JSON 데이터는 URL에 포함될 수 있는 문자만으로 생성
  * HMAC 알고리즘 사용으로 비밀키 또는 RSA를 이용한 Public Key / Private Key 쌍으로 서명 가능

\


*   구조

    ![](https://blog.kakaocdn.net/dn/wkyhk/btq3lTK5qO8/ln4LOYr9hC6unnPkTSD1fk/img.png)

    `.`을 구분자로 나누어지는 세가지 문자열의 조합

    * `Header`
      * 알고리즘과 토큰 타입을 포함
      * "alg" : 정보를 암호화할 해싱 알고리즘 지정
      * "typ" : 토큰의 타입 지정
    * `Payload`
      * 토큰에 저장할 정보를 가짐
      * Claim형태(key, value로 이루어진 한쌍의 정보)로 이루어짐
        * Registered Claim
          * 서비스에서 필요한 정보들이 아닌, 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임
          * 해당 클레임의 사용은 전부 선택적
        * Public Claim
          * 충돌이 방지된 이름을 가지고 있어야함
          * 충돌을 방지하기 위해 클레임 이름을 URI형식으로 생성
        * Private Claim
          * 서버와 클라이언트, 서비스와 서비스간에 협의하에 사용되는 클레임
          * 공개 클레임과 달리 이름이 중복되어 충돌 발생 가능
          * 민감한 정보는 불포함 또는 암호화 처리가 필요
    * `Signature`
      * 인코딩된 Header와 Payload를 더한 뒤 비밀키로 해싱하여 생성
      * 토큰의 위변조 여부 확인 시 사용
        * Header 및 Payload는 단순 인코딩된 값으로 해커가 복호화와 조작 가능
        * Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없음

\


* 토큰 인증 과정
  1. `클라이언트`가 서버로 로그인 **요청**을 보냄
  2. `서버`는 **검증** 후 클라이언트 고유 ID등의 정보를 Payload에 담고, 암호화할 비밀키를 사용해 **Access Token(JWT) 발급**
  3. `클라이언트`는 전달받은 **토큰을 저장**해두고, 서버에 요청할 때마다 토큰을 **요청 헤더 Authorization**에 포함시켜 함께 전달
  4. `서버`는 토큰의 Signature 을 비밀키로 **복호화**한 다음, 위변조 여부 및 유효 기간 등을 확인 후 **유효한 토큰이라면 요청에 응답**

\


### AccessToken

* 클라이언트에서 요청한 로그인이 성공한 경우, 서버는 AccessTocken 발급
* 사용자
  * 발급받은 토큰 정보를 기억하고 있음
  * 서버 호출시 헤더에 해당 토큰을 담아 호출
*   서버

    * AccessToken을 DB나 파일에 저장하지 않았으므로 미리 정의된 비밀키를 이용해 비교하여 인증 처리

    > 이와 같은 이유로 서버는 특정 사용자의 접속을 강제로 만료시키기 어려움

\
\


### RefreshToken

![](https://blog.kakaocdn.net/dn/ApO9R/btq3z6qnp10/WDnbM8Nq2U57kOhzRcKJkK/img.png)

* 개념
  * 한번 발급되면 만료기간까지 계속 사용가능하므로 탈취시 위험하다는 단점을 해결하기 위해 사용
  * Access Token, Refresh Token으로 이중으로 나누어 인증 진행
  * Access Token의 유효기간을 짧게 만들고, 유효기간이 만료될 때마다 Refresh Token을 통해 새로운 Access Token을 만듦

\


* 특징
  * 클라이언트에서 로그인을 요청을 하고 성공을 할 경우, 기존 AccessToken 외에 추가로 RefreshToken을 발급
  * AccessToken 에 비해 긴 만료시간을 갖도록 설정

\


* 클라이언트 측
  * AccessToken이 만료되었을 시 추가로 받았던 RefreshToken을 사용하여 재발급 요청 진행

\


* 서버 측
  * 유효한 RefreshToken이 오면 추가로 AccessToken 과 RefreshToken을 다시 발급
  * RefreshToken의 경우 서버 Storage에 따로 저장하며 이후 검증에 사용
    * 이로인해 추가적인 I/O작업 필요하며 이는 별도의 I/O작업이 없다는 JWT의 빠른 인증처리의 특징에 상반되는 부분임

\


* 장점
  * 토큰이 탈취되더라도 제한된 기간만 접근 가능
  * RefreshToken에 대한 만료 강제 설정 가능

\


* 단점
  * 클라이언트는 AccessToken 만료시 갱신하는 로직을 구현해야 함
  * 서버는 별도의 storage 필요

\
\


### Ref

[1. JWT 토큰 인증과 (쿠키, 세션, 토큰)](https://jhbljs92.tistory.com/entry/1-JWT-%ED%86%A0%ED%81%B0-%EC%9D%B8%EC%A6%9D%EA%B3%BC-%EC%BF%A0%ED%82%A4-%EC%84%B8%EC%85%98-%ED%86%A0%ED%81%B0)\
[JWT(Json Web Token) 소개 및 활용](https://mellowp-dev.tistory.com/8)
