Ideveloper's
Thinking

ideveloper
Front end Developer who steadily study
Nov 16, 2019 - 10 min read

클라이언트 식별과 쿠키

이 글은 HTTP 완벽가이드 11장을 참고해 정리한 포스팅입니다.

시작하기에 앞서


웹서버는 다른 수천개의 클라이언트들과 동시에 통신을 합니다. 이 서버들은 클라이언트로부터 받는 모든 요청을 처리하는 것뿐만 아니라, 서버와 통신하고 있는 클라이언트를 추적해야 할 수도 있습니다.

ex)

  • 개별 인사
    • 온라인 쇼핑이 개인에게 맞춤화된, 사용자에게 특화된 내용 제공하는 경우
  • 사용자 맞춤 추천
    • 고객의 흥미가 무엇인지 학습해 고객이 좋아할 것이라 예상되는 제품들을 추천하는 경우
  • 저장된 사용자 정보
    • 복잡한 주소나, 신용카드 정보를 매번입력하는 것은 번거로우므로, 사용자 식별을 통해 사용자 정보를 쉽게 불러올 경우
  • 세션 추적
    • 사이트에서 사용자가 사이트와 상호작용 할 수 있게 사용자의 상태를 남기는 경우 (장바구니 기능), HTTP 트랜잭션은 상태가 없으므로 이러한 상태 유지를 위해 HTTP 트랜잭션 식별할 방법 필요

위에서 볼 수 있듯 다양한 케이스에서 사용자를 추적해야 하는데, HTTP가 사용자를 식별하는데 사용하는 기술은 아래와 같습니다.

  • 사용자 식별 관련 정보를 전달하는 HTTP 헤더
  • 클라이언트 IP 주소 추적으로 알아낸 IP 주소로 사용자를 식별
  • 사용자 로그인 인증을 통한 사용자 식별
  • URL에 식별자를 포함하는 기술인 뚱뚱한(fat) URL
  • 식별 정보를 지속해서 유지하는 강력하면서도 효율적인 기술인 쿠키

HTTP 헤더 💡


헤더이름 헤더타입 설명
From 요청 사용자의 이메일 주소
User-Agent 요청 사용자의 브라우저
Referer 요청 사용자가 현재 링크를 타고 온 근원 페이지
Authorization 요청 사용자 이름과 비밀번호
Client-ip 확장(요청) 클라이언트의 IP 주소
X-Forwarded-For 확장(요청) 클라이언트의 IP 주소
Cookie 확장(요청) 서버가 생성한 ID 라벨

From, User-Agent, Referer 🙋🏻‍♂️


From

  • From 헤더는 사용자의 이메일 주소를 포함합니다.
  • 이상적으로는 각 사용자가 서로 다른 이메일 주소를 가지므로, From 헤더로 사용자를 식별할 수 있습니다.
  • 악의적인 서버가 이메일 주소를 모아서 스팸 메일을 발송하는 문제가 있어 from 헤더를 보내는 브라우저는 많지 않습니다.

User-Agent

  • 사용자가 쓰고 있는 브라우저의 이름과 버전 정보, 어떤 경우에는 운영체제에 대한 정보까지 포함하여 서버에게 알려줍니다.
  • 특정 브라우저에서 제대로 동작하도록 콘텐츠를 최적화 할 수는 있지만, 특정 사용자를 식별하는 데는 큰 도움이 되지는 않습니다.

ex): User-Agent 예시

image

Referer

  • 사용자가 현재 페이지로 유입하게 한 웹페이지의 URL을 가리킵니다.
  • 사용자의 웹 사용 행태나, 사용자의 취향을 더 잘 파악할 수 있습니다.

위의 From, User-Agent, Referer 헤더들은 확실히 식별하기에는 부족한 정보를 가집니다.

클라이언트 IP 주소 (+ X-Forwarded-for, Client-ip) 🖥


  • 이 방식은 사용자가 확실한 IP 주소를 가지고 있고, 그 주소가 좀처럼(혹은 절대) 바뀌지 않고, 웹 서버가 요청마다 클라이언트의 IP를 알 수 있다면 문제없이 동작합니다.
  • 클라이언트의 IP 주소는 보통 HTTP 헤더에 없지만 웹 서버는 HTTP 요청을 보내는 반대쪽 TCP 커넥션의 IP 주소를 알아 낼수 있습니다.

위와 같은 특징이 있는 반면 아래와 같은 약점을 가지기도 합니다.

  • 클라이언트 IP 주소는 사용자가 아닌, 사용하는 컴퓨터를 가리킵니다. 만약 여러 사용자가 같은 컴퓨터를 사용한다면 그들을 식별할 수 없을 것입니다.
  • 많은 인터넷 서비스 제공자(ISP)는 사용자가 로그인하면 동적으로 IP주소를 할당합니다. 로그인한 시간에 따라, 사용자는 매번 다른 주소를 받으므로, 웹 서버는 사용자를 IP 주소로 식별할수 없습니다.
  • 많은 사용자가 네트워크 주소 변환 방화벽(Network Address Translation) 방화벽을 통해 인터넷을 사용하기 때문에 실제 IP주소를 내부에서 사용하는 하나의 방화벽 IP주소로 변환하기 떄문에 식별이 어렵습니다.
  • HTTP 프락시와 게이트웨이는 원 서버에 새로운 TCP 연결을 합니다. 웹서버는 클라이언트 IP 주소 대신 프락시 서버 IP 주소를 봅니다. 일부 프락시는 원본 IP를 보존하기 위해 Client-ip 나, X-Forwarded-for HTTP 같은 확장 헤더를 추가하여, 이문제를 해결하려 했습니다. 하지만 모든 프락시가 이런 식으로 동작하진 않습니다.

image

사용자 로그인 (Authorization) 🔑


  • IP 주소로 사용자를 식별하려는 수동적인 방식보다, 웹 서버는 사용자 이름과 비밀번호로 인증(로그인)할 것을 요구해서 사용자에게 명시적으로 식별 요청을 할 수 있습니다.
  • HTTP는 WWW-AuthenticateAuthorization 헤더를 사용해 웹 사이트에 사용자 이름을 전달하는 자체적인 체계를 가지고 있습니다.
  • 한번 로그인하면, 브라우저는 사이트로 보내는 모든 요청에 이 로그인 정보를 함께 보내므로 웹서버는 로그인 정보를 항상 확인 할수 있습니다.
  • 서버에서 사용자가 사이트에 접근하기 전에 로그인을 시키고자 한다면 HTTP 401 Login Required 응답 코드를 브라우저에 보낼 수 있습니다.

image

뚱뚱한 URL 🍔


  • 사용자의 상태 정보를 포함하고 있는 URL을 뚱뚱한 URL이라고 부릅니다.
  • 웹서버와 통신하는 독립적인 HTTP 트랜잭션을 하나의 '세션' 혹은 '방문'으로 묶는 용도로 뚱뚱한 URL을 사용할 수 있습니다.

아래는 Amazon.com에서 사용자에게 식별번호를 할당해 추적하는 예입니다. 20658007011 라는 특정 값이 URL에 계속 붙어 사용자를 추적하는것을 확인 할수 있습니다.

image

이러한 방식은 여러 문제가 있는데, 아래와 같습니다.

  • 못생긴 URL
    • 브라우저에 보이는 뚱뚱한 url은 사용자들에게 혼란을 줍니다.
  • 공유하지 못하는 URL
    • url에 세션에 대한 상태 정보를 포함하기 때문에, 개인정보를 본의아니게 공유하게 됩니다.
  • 캐시를 사용할 수 없음
    • url로 만드는것은, url이 달라지기 때문에 기존 캐시에 접근할 수 없다는 것을 말합니다.
  • 서버 부하 가중
    • 서버는 뚱뚱한 URL에 해당하는 페이지를 그려야 합니다.
  • 이탈
    • URL 세션에서 이탈하면, 지금까지의 진척상황들이 초기화 되고 다시 처음부터 시작되어야 할 것입니다.
  • 세션간 지속성의 부재
    • url을 북마킹 하지 않는 이상, 로그아웃하면 모든 정보를 잃습니다.

쿠키 🍪


  • 쿠키는 사용자를 식별하고 세션을 유지하는 방식 중에서 현재까지 가장 널리 사용하는 방식입니다.
  • 쿠키는 새로운 HTTP 헤더를 정의합니다.
  • 쿠키는 캐시와 충돌할 수 있어, 대부분의 캐시나 브라우저는 쿠키에 있는 내용물을 캐싱하지 않습니다.

쿠키의 타입

  • 세션 쿠키
    • 사용자가 사이트를 탐색할때, 관련한 설정과 선호 사항들을 저장하는 임시쿠키
    • 사용자가 브라우저를 닫으면 삭제
  • 지속 쿠키
    • 디스크에 저장되어, 브라우저를 닫거나 컴퓨터를 재시작하더라도 남아있음.
    • 사용자가 주기적으로 방문하는 사이트에 대한 설정 정보나 로그인 이름을 유지하려고 사용

다른점

  • 파기되는 시점
    • 쿠키는 Discard 파라미터가 설정되어 있거나, 파기되기까지 남은 시간을 가리키는 Expires 혹은 Max-Age 파라미터가 없으면 세션 쿠키가 됩니다.

쿠키의 동작 방식

  • A) 처음 사용자가 웹 사이트를 방문하면 서버는 사용자에 대해서 아무것도 모릅니다.
  • B) 서버는 사용자를 식별하기 위한 값을 쿠키에 할당합니다. 쿠키는 이름=값 형태의 리스트를 가지고, 그 리스트는 Set-Cookie 혹은 Set-Cookie2 같은 HTTP 응답헤더에 기술해 사용자에게 전달합니다.
  • C) 브라우저는 서버로 온 헤더에 있는 쿠키 콘텐츠를 브라우저 쿠키 데이터베이스에 저장하고, 브라우저는 추후 요청에 서버가 이 사용자에게 할당했던 쿠키를 cookie 요청헤더에 기술해 전송합니다.

image

사이트마다 각기 다른 쿠키들

브라우저는 수백, 수천개의 쿠키를 가질 수 있지만, 브라우저가 쿠키 전부를 모든 사이트에 보내지 않는데, 그이유는 아래와 같습니다.

  • 쿠키를 모두 전달하면 성능이 크게 저하됩니다.
  • 쿠키들은 대부분 서버 특화된 이름/값 쌍을 포함하고 있기 때문에, 대부분 사이트에서는 인식하지 않는 무의미한 값입니다.
  • 모든 사이트에 쿠키 전체를 전달하는 것은, 특정사이트에서 제공한 정보를 신뢰하지 않는 사이트에 가져갈수 있으므로 잠재적인 개인정보 문제를 일으킬 수 있습니다.

쿠키 Domain 속성

  • 서버는 쿠키를 생성할 때, Domain 속성을 기술해 어떤 사이트가 그 쿠키를 읽을 수 있는지 제어할 수 있습니다.

아래 예는, 브라우저가 user="ideveloper"라는 쿠키를 .ideveloper2.dev 도메인을 가지고 있는 모든 사이트에 전달한다는 의미입니다.

Set-cookie: user="ideveloper"; domain="ideveloper2.dev"

쿠키 Path 속성

  • 웹 사이트 일부에만 쿠키를 적용할 수도 있습니다.
  • URL 경로의 앞부분을 가리키는 path 속성을 기술해, 해당경로에 속하는 페이지에만 쿠키를 전달합니다.

예를 들어, ideveloper2.dev/blog를 접속했을때 link=blog라는 쿠키를 추가로 서버에서 전달받게 되는것입니다.

Set-cookie: link=blog; domain="ideveloper2.dev"; path=/blog/

쿠키 구성요소

  • 현재 사용되는 쿠키 명세에는 Version 0 쿠키(넷스케이프 쿠키)Version 1 쿠키가 있습니다. Version 1 쿠키는 Version 0 쿠키의 확장으로 널리 쓰이지는 않습니다.

Version 0 쿠키

  • 최초의 쿠키 명세는 넷스케이프가 정의했습니다.
  • version 0 쿠키는 Set-cookie 응답헤더와 cookie 요청 헤더와 쿠키를 조작하는 데 필요한 필드들을 정의하였습니다.
Set-Cookie: name=value [; expires=date] [; path=path] [; domain=domain] [; secure]
Cookie: name1=value1 [;name2=value2]

version 0 Set-Cookie 헤더

  • 더 자세한 정보는 아래 링크에서 확인 가능합니다.

https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Set-Cookie

Set-Cookie 속성 설명과 용례 설명 필수 여부
이름=값 Set-Cookie: name="ideveloper" 필수
Expires Set-Cookie: expires=Wednesday, 09-Nov-99 23:12:40 GMT 사용할 수 있는 타임 존은 GMT뿐, (요일, DD-MM-YY HH:MM:SS GMT) 선택
Domain Set-Cookie: domain="ideveloper.dev" 선택
Path Set-Cookie: path="/blog" 선택
Secure Set-Cookie: secure http ssl보안 연결 사용할때만 보냄 선택

Version 1 쿠키

  • Set-Cookie2 헤더와 Cookie2 헤더 사용
  • 모든 브라우저나 서버가 완전히 지원하지는 x
  • 주요 변경사항
    • 쿠키마다 목적 설명하는 설명문 있음
    • 파기 주기 상관없이 브라우저 닫히면 강제로 삭제 가능
    • 초 단위의 상대 값으로 쿠키의 생명주기 결정 할수 있음
    • URL 포트번호로도 쿠키 제어 가능
    • 도메인, 포트, 경로 필터가 있으면 cookie헤더에 담아 되돌려 보냄
    • 호환되는 버전 번호
    • cookie 헤더에 $접두어가 있음

쿠키와 세션 추적

  • 쿠키는 사이트에 수차례 트랜잭션을 만들어내는 사용자를 추적하는데 사용합니다.
  • 전자상 거래 사이트는 사용자의 온라인 쇼핑카트를 유지하려 세션쿠키를 사용합니다.

아래 예는 amazon.com에서 일어나는 쿠키를 활용한 트랜잭션의 연속과정을 보여줍니다.

a) amazon.com 루트 페이지 요청

b) 서버는 클라이언트를 리다이렉트 시킴

c) 클라이언트는 리다이렉트 url로 요청 보냄

d) 서버는 응답에 두개 세션 쿠키 기술하고 사용자를 다른 url로 리다이렉트 시키고, 클라이언트는 다시 이 쿠키들을 첨부해 요청을 보냄.

e) 클라이언트는 새로운 url 요청을 앞서 바든 두개의 쿠키와 함께 보냄

f) 서버는 home.html 페이지로 redirect 시키고 쿠키 두개를 더 첨부함

g) 클라이언트는 home.html 페이지를 가져오고 총 4개의 쿠키를 전달함.

h) 서버는 콘텐츠를 보냄. image

쿠키와 캐싱

  • 쿠키 트랜잭션과 관련된 문서를 캐싱하는 것은 주의해야 합니다. 이전 사용자의 쿠키가 다른 사용자에게 할당돼버리거나, 누군가의 개인 정보가 다른 이에게 노출되는 최악의 상황이 일어날수도 있습니다.

쿠키와 캐싱 관련해 주의할점

  • 캐시되지 말아야 할 문서가 있다면 표시하라
    • Cache-Control: no-cache="Set-Cookie" 를 기술해 명확히 표시
    • Cache-Control: public 을 사용해, 웹의 대역폭을 더 절약
  • Set-Cookie 헤더를 캐시하는것에 유의하라
    • 응답이 Set-Cookie 헤더를 가지고 있으면 본문은 캐시할수 있지만, 헤더를 캐시하는것은 주의 필요
    • 같은 Set-Cookie 헤더를 여러 사용자에게 보내면 사용자 추적에 실패
    • 어떤 캐시는 응답 저장 전 Set-Cookie 헤더를 제거하기도 함
    • 원서버는 Cache-Control: must-revalidate, max-age=0 과 같은 헤더를 캐시된 문서에 추가함으로써 재검사가 일어나게 할 수 있음.
  • Cookie 헤더를 가지고 있는 요청을 주의하라
    • 요청이 Cookie 헤더와 함꼐 오면, 결과 콘텐츠가 개인정보를 담고 있을수도 있다는 힌트 (개인정보는 캐시되지 않도록 표시되어야 하지만, 그 표시를 하지않는 서버도 있음)
    • 보수적인 캐시는 Cookie 헤더가 포함된 요청에 응답으로 오는 문서는 캐시하지 않음

쿠키, 보안 그리고 개인정보

  • 쿠키를 사용하지 않도록 비활성화 시킬 수 있고, 로그 분석 같은 기법으로 대체하는것도 가느하므로, 보안상으로 그자체가 위험한것은 아님.
  • 원격 DB에 개인정보를 저장하고 데이터의 key값을 쿠키에 저장하는 바식을 사용하면 클라이언트와 서버 사이에 예민한 데이터가 오가는것을 방지 할 수 있음.
  • 개인정보를 다루거나 사용자를 추적 하는기술은 잘못된 용도로 사용할 수 있기 때문에 항상 조심하는것이 좋음.
Powered with by Ideveloper