HTTP의 특성과 쿠키, 세션, 토큰

최범수·2021년 10월 17일
35
post-thumbnail
post-custom-banner

서버가 어떻게 클라이언트를 식별하는지에 대해 작성한 글입니다.
우리가 익히 알고 있던 쿠키, 세션, 토큰은 결국엔 HTTP의 특성으로부터 파생되어 생겨난 것이란 걸 알게 되었습니다. HTTP의 어떤 특성이 쿠키를 만들어냈는지, 세션과 토큰은 어떤 이유로 생겨났는지를 중심으로 글을 작성했습니다.
틀린 부분이 있다면 댓글로 알려주시면 감사하겠습니다!

HTTP

웹의 동작과정

클라이언트는 서버에게 Request를 보내고, 서버는 클라이언트에게 Response를 보낸다.

각기 다른 클라이언트들이 하나의 서버에 요청을 보낼 수 있는데, 모두 다른 방식으로 요청을 보내면 서버가 일일이 대응할 수가 없다. 따라서 HTTP라는 통신규약을 지정하여 모든 요청과 응답은 HTTP 양식에 맞게 보내야 한다.


HTTP의 특성

Connectionless

HTTP 통신을 하기 위해서는 클라이언트와 서버가 연결이 되어있어야 한다. 이 커넥션을 유지하는 것 자체도 부담이고, 클라이언트가 늘어나서 커넥션의 개수가 많아지면 서버에 많은 부담이 된다.
따라서 HTTP는 통신을 한번 할 때 클라이언트와 서버를 연결하고, 통신이 끝나면 바로 연결을 끊는다. 이를 통해 서버 자원을 효율적으로 관리하고 여러 클라이언트의 요청에 대응한다.

한 클라이언트가 여러번의 요청을 보내도 커넥션은 계속 끊어졌다, 연결됐다를 반복한다. 이러한 HTTP의 특성을 Connectionless라고 한다.
(HTTP 1.1부터 일정 시간동안 계속 요청을 보내면 한번의 커넥션 연결로 처리하며 이를 지속 커넥션이라 한다.)


장점

  • 서버의 부하를 줄여서 더 많은 클라이언트의 요청을 처리할 수 있다.

단점

  • 커넥션을 계속 끊어버리기 때문에 여러번 요청한 클라이언트와 커넥션을 계속 새로 만들어주어야 한다.

Stateless

HTTP는 이전 요청의 상태를 기록하지 않기 때문에 서버는 클라이언트를 식별할 수 없다.

커넥션이 계속 연결되어 있으면 요청을 보낸 클라이언트가 누구인지 지속적으로 파악할 수 있지만, 커넥션은 끊어지기 때문에 다음번 요청이 이전에 요청을 보낸 클라이언트인지 새로 요청을 보낸 클라이언트인지 알 수 없다.

또한 "서버는 클라이언트의 상태를 보존하지 않는다." 즉, 이전 요청이 어떻게 끝났느냐에 따라 다음 요청이 영향을 받지 않고 모든 요청이 독립적이다. 따라서 클라이언트를 식별할 수 없다.

예시를 통해 Stateless를 살펴보자. 아래는 아이스 아메리카노 2잔을 주문하는 상황이다.

Stateful의 경우, 클라이언트가 여러번에 걸쳐 주문을 진행해도, 카페 직원은 여태까지의 주문 사항을 기억하고 있으므로 정상적으로 주문을 처리할 수 있다.

Stateless의 경우, 카페 직원은 클라이언트가 한 말을 바로 잊어버린다. 따라서 클라이언트가 아메리카노를 주문하고 "차가운거요"라고 주문하면, 카페 직원은 "어떤걸 차갑게 달라는거죠?"라고 응답하게 된다.

이전 상태를 보존한다면 이전 요청의 내용을 기억하여 다음 요청에 반영할 수 있다. 그러나 Stateless는 이전 요청이 무엇이였는지 기억하지 않기 때문에 한번의 요청에 모든 내용을 다 전달해야 한다.


서버는 여러대의 컴퓨터로 구성될 수도 있다. 마찬가지로 카페 직원도 여러명일 수 있다.

Stateful인 경우, 카페 직원이 인수인계 없이 중간에 교체되면 주문을 정상적으로 처리할 수 없다.
마찬가지로 서버 컴퓨터끼리 요청 사항이 공유되지 않은 상태에서, 다른 서버 컴퓨터가 요청을 받으면 제대로 된 응답을 처리할 수 없다.

Stateless의 경우, 모든 주문 사항을 한번에 말하므로 어느 카페 직원이 주문을 받더라도 처리할 수 있다.
마찬가지로 요청 한번에 모든 요구사항이 들어있기 때문에 어떤 서버 컴퓨터가 요청을 받아도 제대로 응답을 처리할 수 있다.


장점

  • 이전 요청을 기억할 필요가 없으므로, 이를 위한 저장 공간이 필요없다.
  • 서버 디자인을 단순하게 만든다.
  • 서버가 여러대의 컴퓨터로 구성된 경우, 어떠한 컴퓨터가 요청을 받더라도 응답이 가능하다.

단점

  • 클라이언트를 식별하기 어렵다.
  • 매 요청마다 추가 정보가 주어야 한다.


웹의 개인화

웹이 발전함에 따라 각 클라이언트에 맞게 개인화된 웹 사이트를 제공하고자 하는 욕구가 발생했다.

  • (사이트 내에서) 신발을 많이 검색한 사람에게는 신발을 추천 상품으로 보여주기
  • 신규 유저인 경우, 웰컴 메세지 보여주기
  • "7일간 보지 않기"를 선택한 유저에게는 팝업을 띄워주지 않기
  • 기본 배송지, 아이디 저장 기능 등

개인화를 위해서 여러 클라이언트들을 서버가 식별할 수 있어야 했다. HTTP는 Connectionless, Stateless였으므로 클라이언트를 식별할 수가 없었고, 초기 웹 개발자들은 클라이언트를 식별하기 위한 방법들을 각기 개발했다.


HTTP Header

HTTP 헤더의 정보를 분석하여 사용자를 어느정도 구분할 수 있었다.

  • From : 사용자의 이메일 주소
  • User-Agent : 사용자의 브라우저 정보
  • Referer : 사이트에 유입된 경로

클라이언트로부터 요청이 들어왔을때, 위 정보들을 사용하여 이 클라이언트가 이전에 방문한 어떤 클라이언트와 같은지 식별하였다. 그러나 확실하게 식별하기에는 정보가 부족했다.


IP 추적

초기 웹 개발자들은 IP 주소를 이용해 클라이언트를 식별하려고도 했다.

그러나 IP는 컴퓨터를 식별하는 것이지 실제 사용자를 식별할 수는 없었다. 여러 사람이 하나의 IP로 접근할 수도 있고, 한 사람이 여러 개의 IP로 접근할 수도 있었다.


로그인

웹 서버가 클라이언트에게 인증 정보를 요청하는 방식인 로그인을 통해 클라이언트를 식별할 수 있었다.

그러나 매 요청마다 인증 정보를 요구하는 것은 사용자 입장에서 너무 귀찮은 일이다. 개인화된 웹을 위해 모든 페이지 전환, 요청마다 아이디와 비밀번호를 달라고 요구하면 사용자는 차라리 개인화를 하지 말라고 할 것이다.


Fat URL

URL에 고유 ID를 넣어서 클라이언트를 식별하는 방법

클라이언트가 웹 사이트에 방문한 첫 요청에 서버는 고유 ID를 발행하고, 그 값을 URL에 계속 넣어둔다. 사이트 내에서 페이지 이동이 일어나도 해당 아이디를 꼭 URL에 포함시켜서 클라이언트 추적을 놓치지 않도록 한다.

아마존에서는 Fat URL 방식으로 사용자의 행동을 추적하여 개인화된 웹 사이트를 제공했다고 한다.


Fat URL 단점

  1. URL이 못 생겨진다.

  2. URL을 공유할 수 없다.

    특정 사용자의 상태 정보가 누적된 URL이기 때문에 공유하면 개인 정보도 같이 공유하게 된다.

  3. URL을 유지하지 못 하고 이탈할 가능성이 크다.

    사용자가 다른 사이트를 방문하고 다시 돌아오거나, 고유 ID가 누락된 링크를 클릭하면 해당 클라이언트에 대한 식별은 끝이 난다.


위 방식들의 한계로 새로운 클라이언트 식별법이 필요했고, 넷스케이프에서 쿠키를 개발하였고 현재 모든 브라우저에서 쿠키를 지원한다.



Cookie

쿠키는 왜 쿠키일까?

UNIX OS에서 프로그램 사이에 전송되는 작은 데이터 패킷을 "Magic Cookie"라고 불렀는데,
클라이언트에서 서버로 전송되는 작은 데이터라는 개념이 비슷하여 여기서 가져온 것이라 한다.

매직 쿠키라는 용어는 쿠키를 열면 메세지가 나오는 포춘 쿠키에서 파생된 용어라고 한다.


쿠키의 동작방식

HTTP 쿠키는 서버가 클라이언트에게 준 정보를 브라우저에 저장하고, 클라이언트가 요청을 보낼 때 HTTP 헤더에 정보를 담아서 서버에 전달한다.


1. 클라이언트의 첫 HTTP Request

클라이언트가 웹 사이트를 첫 방문하면 서버는 해당 클라이언트를 식별하기 위한 Key-Value 객체를 만든다.
(자바스크립트 객체로 표현했지만, 실제로 이렇게 생겼다는 것은 아니다. 실제로는 String이다.)

{
  Name: "status",
  Value: "lawyer",
  Domain: "www.lawandgood.com",
  Path: "/",
  Expires: "2021-09-30T23:59:59.000Z",
  .
  .
}

2. 서버의 HTTP Response

HTTP 헤더의 Set-Cookie 항목에 쿠키를 담아서 전달한다. 클라이언트는 Set-Cookie 헤더에 있는 쿠키를 브라우저에 저장한다.

꼭 Set-Cookie 헤더를 통해 쿠키를 세팅할 수 있는 것은 아니다. 서버에서 렌더링하는 HTML에 정보를 전달하고 script 태그 내에서 쿠키를 세팅할 수도 있고, 사용자가 어떤 버튼을 눌렀을 때 자바스크립트를 통해 쿠키를 서버 개입 없이 세팅해놓을 수도 있다.

<script>
  setCookie({
    name: 'status',
    value: '{{ user.status }}',
    expires: new Date('2021-09-30 23:59:59'),
    .
    .
  })
</script>

쿠키의 저장위치는 브라우저가 어떻게 쿠키 스토리지를 구현했느냐에 따라 다르다.

크롬의 경우, 데이터를 SQLite에 저장하며 쿠키는 Cookies라는 항목에 쿠키를 습득한 사이트 별로 저장된다.


클라이언트의 첫 요청 이후, 다음 요청부터는 쿠키가 HTTP 헤더에 포함된다.

브라우저가 가지고 있는 쿠키의 개수는 몇백개가 되는데, 모든 사이트를 방문하거나 API 요청을 보낼 때마다 몇백개의 쿠키를 HTTP 헤더에 담아서 보내지는 않는다.

쿠키에는 Domain과 Path라는 속성이 있다.

  • Domain : HTTP 요청을 보낼 주소의 도메인이 Domain 속성값과 같은 경우에만 쿠키를 보낸다.
  • Path : HTTP 요청을 보낼 주소의 URL 경로가 Path 속성값과 같은 경우에만 쿠키를 보낸다.

이렇게 쿠키를 서버로 보내서, 서버가 클라이언트를 식별할 수 있도록 한다.


HTTP Status Management Mechanism

쿠키의 기본 발상은 브라우저가 서버의 정보를 저장하고, 사용자가 해당 서버에 접근할 때마다 그 정보를 함께 전송하는 것이다.

저장되는 서버 정보가 쿠키이고, 브라우저는 쿠키를 저장할 책임이 있다. 이러한 시스템을 "클라이언트 측 상태", "HTTP 상태 관리 체계" 라고 한다.



쿠키의 종류

쿠키는 2종류가 있고, 둘의 차이점은 파기 시점뿐이다.

1. 세션쿠키

만료일을 설정하지 않기 때문에 브라우저를 종료하면 파기된다. (만료일은 Expires, Max-Age 로 설정한다.)

사용자가 사이트를 탐색할 때 선호 사항, 임시 설정 등을 저장하는 쿠키

  • 최근 본 상품
  • 최근 검색어

2. 지속쿠키

디스크에 저장되어서 만료일까지는 브라우저를 끄거나 재부팅하여도 남아있는다.

다음 방문에도 영향을 주는 설정 정보나 로그인 정보 등을 유지할 때 사용하는 쿠키

  • 일주일간 팝업 보지 않기
  • 로그인 유지


쿠키의 제약조건과 한계

쿠키 제약조건

  • 브라우저는 총 300개의 쿠키를 저장할 수 있다.
  • 하나의 도메인당 20개의 쿠키를 가질 수 있다. 초과되면 가장 적게 사용된 것부터 삭제한다.
  • 하나의 쿠키는 4KB까지 용량을 차지할 수 있다.

쿠키의 한계

  • 민감한 정보를 그대로 HTTP 통신에 노출하는 경우 탈취당할 수 있다. 아이디와 패스워드를 쿠키에 넣어서 모든 요청마다 인증 정보를 포함하게 할 수 있는데, 통신 과정에서 패킷을 가로채가면 패스워드가 유출될 수 있다.
  • 쿠키의 보안 취약점을 보완하기 위해 "세션"이 등장한다.


Session

세션 동작방식

쿠키가 탈취당할 수 있다는 것을 인지하여, 민감한 정보는 서버에만 저장하고 쿠키에는 서버에 저장된 정보를 찾을 수 있는 키만 전달하는 방식.

쿠키를 사용하는 것에는 변함이 없고, 쿠키 값으로 어떤 것을 주느냐가 다르다.


1. 클라이언트의 첫 HTTP Request와 세션 생성

쿠키의 동작방식과 같이 클라이언트가 첫 요청을 보내면 서버는 이 클라이언트를 식별하기 위한 객체를 만든다.

쿠키에서는 이 객체를 바로 HTTP 헤더에 담아서 보내지만, 세션에서는 이를 서버에 저장한다. 데이터베이스에 저장할 수도 있고, 서버의 파일 시스템에 저장할 수도 있다. 이렇게 세션이 저장되는 공간을 세션 스토리지라고 한다.


2. 서버의 HTTP Response

서버는 세션 스토리지에 저장된 정보를 식별할 수 있는 세션 ID를 쿠키에 담아서 클라이언트에게 전달한다.

세션 스토리지가 데이터베이스라고 한다면, 쿠키가 담고 있는 값은 단지 데이터베이스의 어떤 로우를 가리키는 PK일뿐이다. 따라서 쿠키가 탈취당해도 쿠키로부터 얻을 수 있는 정보는 없다.


3. HTTP with Session

클라이언트의 두번째 요청부터는 쿠키가 함께 들어온다.

서버는 쿠키를 받아서 세션 스토리지에서 세션 객체를 찾는다. 세션 객체로부터 사용자정보를 얻고 개인화된 응답을 보내준다.

세션의 핵심은 HTTP 통신 상에서는 어떠한 민감한 정보도 오가지 않는다는 것이다. 민감한 정보는 오직 서버와 세션 스토리지에서만 다뤄지고 외부로 노출되지 않는다.



세션의 한계

  • 쿠키에 담긴 정보가 있는 그대로는 의미 없지만, 탈취한 쿠키를 이용해 서버에 요청을 보내면 정보가 유출될 수 있다. (세션 하이재킹)
  • 서버에 정보를 저장해야 하기 때문에 메모리 공간을 차지한다.
  • 쿠키로부터 받은 세션 ID로 세션 스토리지를 탐색해야 하는 시간이 든다.
  • 동시 접속자가 많은 서비스의 경우 서버 과부하의 원인이 되어, 서버에 정보를 저장하지 않는 "토큰"이 등장


Token

토큰 동작방식

서버는 인증에 필요한 정보들을 암호화시켜 토큰을 발행하고, 클라이언트는 발행받은 토큰을 HTTP 헤더에 계속 넣어서 요청을 보내는 방식


1. 클라이언트의 인증 Request

클라이언트는 아이디, 패스워드 등의 인증정보를 HTTP 요청에 담아서 서버에 전달


2. 서버의 인증 정보 확인 및 Response + Token

서버는 클라이언트로부터 받은 인증 정보가 유효한지 확인하고, 토큰을 HTTP 응답에 담아서 전달

토큰은 Secret Key로 암호화되어 있고, 유효기간이 설정되어 있다.


3. HTTP with Token

클라이언트는 서버로부터 발급받은 토큰을 HTTP 헤더에 담아서 요청을 보내고, 서버는 토큰이 유효한지 검사하여 인증 여부를 판별한다.

토큰은 Secret Key로 복호화하여 유효한지 아닌지 판별할 수 있기 때문에 별도의 저장공간이 필요하지 않다. 따라서 세션 방식의 단점인 서버 과부하를 줄여줄 수 있다.



토큰의 한계

  • 이미 발급된 토큰은 유효기간이 만료되기 전까지 계속 사용할 수 있기 때문에, 악의적으로 이용될 수 있다. 따라서 토큰 유효기간을 짧게 하고 Refresh Token을 새로 발급해야 한다.
  • 토큰의 길이가 쿠키, 세션에 비해 길어서 인증이 필요한 요청이 많을 때 서버 자원낭비가 발생한다.


정리

  • HTTP의 특성
    • Connectionless
    • Stateless
  • HTTP의 특성으로 비롯된 웹의 개인화와 인증을 위한 방법
    • 쿠키 이전의 방식 (HTTP Header, IP, Fat URL, ...)
    • 쿠키
    • 세션
    • 토큰
  • 각 방법의 단점을 보완하기 위해 다음 방법이 등장
    • 쿠키 이전의 방식 : 사용자를 정확하게 식별할 수가 없다 → 브라우저에 명시적으로 누구인지 기록하자!
    • 쿠키 : 쿠키를 탈취당하면 개인정보가 유출된다 → 민감한 정보는 브라우저에 주지 말고 서버에 두자!
    • 세션 : 세션을 저장하기 위한 공간과 응답 속도가 지연된다 → 저장하지 말고 암호화한 토큰을 줘버리자!
    • 토큰 : 토큰을 탈취하여 악의적으로 사용할 수 있다 → Refresh 토큰을 써서 유효기간을 짧게 하자!


References

HTTP 완벽 가이드 - YES24

Why are internet cookies called cookies? - inLIFE

Why Are Internet Cookies Called Cookies?

HTTP, Stateless, Connectionless, HTTP 메시지 개념

쉽게 알아보는 서버 인증 1편(세션/쿠키 , JWT)

profile
프론트엔드 개발자
post-custom-banner

9개의 댓글

comment-user-thumbnail
2021년 10월 26일

정리가 진짜 깔끔합니다ㅠㅠ 잘 보고 갑니다!

1개의 답글
comment-user-thumbnail
2021년 10월 27일

👍

답글 달기
comment-user-thumbnail
2021년 10월 27일

https://bediroglunakliye.com/gebze-evden-eve-nakliyat/
Gebze Evden Eve Nakliyat Fiyatları konusunda sizleri endişeye ve zora sokacak hiçbir durum söz konusu değildir. Nakliyat fiyatlandırma konusunda bir sorununuz olmaması için sizinleyiz.

답글 달기
comment-user-thumbnail
2021년 10월 29일

stateless에 대해서 이해가 잘 가지 않았었는데 깔끔한 비유에 이마를 탁 치고 가네요 ㅠㅠ 감사합니다!

1개의 답글
comment-user-thumbnail
2021년 11월 4일

범수햄 잘읽었소~

1개의 답글
comment-user-thumbnail
2021년 12월 9일

You have really explained this topic in great detail, your article is quite long, thank you for that. motox3m

답글 달기