개발도서 읽기/HTTP 완벽 가이드

[3. 식별, 인가, 보안] 11장) 클라이언트 식별과 쿠키

까연 2021. 5. 16. 18:41

개별 접촉

HTTP는 익명으로 사용하며 상태가 없고 요청과 응답으로 통신하는 프로토콜이다. 현대의 웹 사이트들은 개인화된 서비스를 제공하고 싶어하고 사용자들에 대해 더 많은 것을 알고 기록하고 싶어한다.

  • 개별 인사: 온라인 쇼핑이 개인에게 맞춰 있는 것처럼 느끼게 하려고 사용자에게 특화된 페이지 내용을 만든다.
  • 사용자 맞춤 추천: 온라인 상점은 고객의 흥미가 무엇인지 학습해 좋아할 것이라 예상되는 제품을 추천한다.
  • 저장된 사용자 정보: 복잡한 주소와 카드 정보를 매번 입력하지 않고 저장된 사용자 정보를 사용할 수 있다.
  • 세션 추척: 사용자가 사이트와 상호작용할 수 있게 사용자의 상태를 남긴다. (쇼핑몰 장바구니 기능)

 

서버가 통신하는 대상을 식별하는 데 사용하는 기술들

- HTTP 헤더

정보를 전달하는 가장 일반적인 일곱 가지 HTTP 요청 헤더

  • From, User-Agent, Referer, Authorization, Client-ip, X-Forwarded-For, Cookie

From 헤더

: 사용자의 이메일 주소를 포함. From 헤더로 사용자를 식별할 수 있으나 악의적인 서버가 스팸 메일을 발송하는 문제가 있어서 잘 보내지 않는다.

 

User-Agent 헤더

: 사용자가 쓰고 있는 브라우저의 이름과 버전 정보를 포함한다. 특정 브라우저에서 그것들의 속성에 맞추어 콘텐츠를 최적화 하기에 유용하지만 사용자를 식별하는 데는 도움되지 않는다.

 

Referer 헤더

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

 

- 클라이언트 IP 주소

: 사용자 식별에 클라이언트 IP 주소를 사용할 경우 사용자가 확실한 IP 주소를 가지고 있고, 주소가 바뀌지 않고, 웹 서버 요청마다 IP를 알 수 있다면 문제없이 동작한다.  그러나 다음과 같은 약점이 존재한다.

 

클라이언트 IP 주소로 사용자를 식별하는 방식의 약점

  • IP주소는 사용자가 아닌 사용자 컴퓨터를 가리키므로, 만약 여러 사용자가 같은 컴퓨터를 사용하면 그들을 식별할 수 없다.
  • 많은 인터넷 서비스 제공자는 사용자가 로그인하면 동적으로 IP 주소를 할당한다.
  • 보안을 강화하고 부족한 주소들을 관리하려고 방화벽을 통해 인터넷을 사용한다. NAT 방화벽 장비들은 IP 주소를 방화벽 뒤로 숨기고 클라이언트의 실제 IP 주소를 내부에서 사용하는 하나의 방화벽 IP 주소로 변환한다.
  • 보통 HTTP 프락시와 게이트웨이는 원 서버에 새로운 TCP를 연결한다. 따라서 클라이언트의 IP 주소 대신 프락시 IP 주소를 본다.

 

- 사용자 로그인

: 웹 서버는 사용자의 이름과 비밀번호로 인증할 것을 요구해 사용자에게 명시적으로 식별 요청을 할 수 있다.

 

서버에서 사용자가 사이트에 접근하기 전에 로그인을 시키고자 한다면 HTTP 401 Login Required 응답 코드를 브라우저에게 보낸다. 브라우저는 로그인 화면을 보여주고, 다음 요청부터 식별 정보 토큰을 Authorization 헤더에 기술하여 보내고 한 세션이 진행되는 내내 그 사용자에 대한 식별을 유지한다.

 

하지만 사이트를 옮겨다닐 때마다 각 사이트에 로그인을 해야하고 사이트마다 서로 다른 사용자 이름과 비밀번호를 기억해야한다는 문제가 있다.

 

- 뚱뚱한 URL

: 사용자의 상태 정보를 포함하고 있는 URL. 웹 서버와 통신하는 독립적인 HTTP 트랜잭션을 하나의 '세션' 혹은 '방문'으로 묶는 용도로 뚱뚱한 URL을 사용할 수 있다. 사용자가 웹 사이트에 처음 방문하면 ID가 생성되고 URL에 추가되며, 서버는 클라이언트를 뚱뚱한 URL로 리다이렉트 시킨다.

 

뚱뚱한 URL은 사이트를 브라우징하는 사용자를 식별하는 데 사용할 수 있지만, 문제점이 존재한다.

  • 못생긴 URL: 브라우저에 보이는 뚱뚱한 URL은 사용자에게 혼란을 줄 수 있다.
  • 공유하지 못하는 URL: 뚱뚱한 URL에 특정 사용자와 상태 정보가 포함되어 있어 주소를 누군가에게 보내면 개인 정보를 공유하게 되는 꼴
  • 캐시를 사용할 수 없음: URL이 달라지기 때문에 기존 캐시에 접근할 수 없음
  • 서버 부하 가중: 뚱뚱한 URL에 해당하는 HTML 페이지를 다시 그려야함
  • 이탈: 사용자가 링크를 타고 다른 사이트로 이동하거나 특정 URL을 의도치 않게 요청해서 뚱뚱한 URL 세션에서 이탈하기 쉽다.
  • 세션 간 지속성의 부재: 사용자가 URL을 북마킹하지 않는 이상, 로그아웃하면 모든 정보를 잃는다.

 

- 쿠키

: 사용자를 식별하고 세션을 유지하는 방식 중에서 현재까지 가장 널리 사용하는 방식

 

쿠키의 타입

  • 세션 쿠키

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

브라우저를 닫으면 삭제된다.

 

  • 지속 쿠키

주기적으로 방문하는 사이트에 대한 설정 정보나 로그인 이름을 유지하기 위해 사용

디스크에 저장되어 브라우저를 닫거나 재시작하여도 남아있다. 

 

세션 크키와 지속 쿠키는 파기되는 시점만 다르다.

 

쿠키는 어떻게 동작하는가

쿠키는 임의의 이름=값 형태의 리스트를 가지고 리스트는 Set-Cookie 혹은 Set-Cookie2(확장 헤더) 같은 응답 헤더에 기술되어 사용자에게 전달한다.

 

브라우저는 서버로 온 Set-Cookie나 Set-Cookie2 헤더에 있는 쿠키 콘텐츠를 브라우저 쿠키 데이터베이스에 저장한다. 사용자가 다음에 같은 사이트를 방문한다면 브라우저는 서버가 이 사용자에게 할당했던 쿠키를 Cookie 요청 헤더에 기술해 전송한다.

 

쿠키 상자: 클라이언트 측 상태

: 브라우저는 쿠키 정보를 저장할 책임이 있는데, 이 시스템을 클라이어트 측 상태라고 한다. (공식 이름은 HTTP 상태 관리 체계)

 

각 브라우저는 각기 다른 방식으로 쿠키를 저장한다.

 

구글 크롬 쿠키

: Cookies라는 SQLite 파일에 쿠키를 저장한다.

creation_utc(쿠키가 생성된 시점), host_key(쿠키의 도메인), name(쿠키 이름), value(쿠키 값), path(쿠키와 관련된 도메인이 있는 경로), expire_utc(쿠키 파기 시점), secure(쿠키를 ssl 커넥션일 경우에만 보낼지) 등의 필드가 존재한다.

 

마이크로소프트 인터넷 익스플로러 쿠키

: 캐시 디렉터리에 각각의 개별 파일로 쿠키를 저장한다. 파일에 있는 각 쿠키의 첫 번째 줄은 쿠키의 이름, 다음 줄은 쿠키의 값이며 세 번째 줄엔 도메인과 경로가 있다.

 

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

: 브라우저는 수천 개의 쿠키를 가지고 있을 수 있지만, 모든 사이트에 쿠키 전부를 보내진 않는다.

왜냐하면

  1. 쿠키를 모두 전달하면 성능이 크게 저하된다.
  2. 또한 대부분은 서버에 특화된 이름/값 쌍을 갖고 있기 때문에 대부분 사이트에서는 인식하지 않는 무의미한 값이다.
  3. 또한 모든 사이트에 쿠키 전체를 전달하는 것은 개인정보 문제를 일으킬 것이다.

많은 웹 사이트는 광고를 관리하는 협력업체와 계약을 한다. 광고들은 웹 사이트 자체 일부인 것처럼 제작되고 쿠키를 만들어 낸다. 같은 광고사에서 제공하는 다른 웹 사이트에 사용자가 방문하면, 브라우저는 앞에서 만든 지속 쿠키를 다시 광고사 서버로 전송한다. 이 기술에 Referer 헤더를 접목하여 사용자의 프로필과 웹 사이트를 사용하는 습관에 대한 데이터를 구축할 수 있다.

 

쿠키 Domain 속성

: domain 속성을 기술해 어떤 사이트가 그 쿠키를 읽을 수 있는지 제어할 수 있다.

 

쿠키 Path 속성

: URL 경로의 앞부분을 가리키는 Path 속성을 기술해 해당 경로에 속하는 페이지에만 쿠키를 전달

 

ex)

Set-cookie: user="mary17"; domain="airtravelbargains.com"

Set-cookie: pref=compact; domain="airtravelbargains.com"; path=/autos/

 

http://www.airtravelbargains.com/specials.html에 접근할 경우, 

Cookie: user="mary17"

 

http://www.airtravelbargains.com/autos/cheapo/index.html에 접근할 경우, 

Cookie: user="mary17"

Cookie: pref=compact

 

쿠키 구성요소

: Version0과 Version0의 확장인 Version1이 있다. (1은 널리 쓰이지 않음)

 

Version 0(넷스케이프) 쿠키

: Set-Cookie 응답 헤더와 Cookie 요청 헤더와 쿠키를 조작하는데 필요한 필드들을 정의

Set-Cookie 헤더는 쿠키의 이름과 값을 가져야 하고 옵션 속성들(Expires, Domain, Path, Secure)에 대해 세미콜론으로 기술한다.

 

Version 1 쿠키에 추가된 변경 사항

  • 쿠키마다 목적을 설명하는 설명문이 존재
  • 파기 주기에 상관없이 쿠키를 강제로 삭제 가능
  • 절대 날짜 값 대신 초 단위의 상대 값으로 쿠키의 생명주기를 결정할 수 있는 Max-Age
  • URL의 포트번호로도 쿠키를 제어할 수 있다.
  • 도메인, 포트, 경로 필터가 있으면 Cookie 헤더에 담겨 되돌려 보낸다.
  • 호환되는 버전 번호
  • $ 접두어

Version1 Cookie2 헤더와 버전 협상

: Cookie2 요청 헤더는 각기 다른 쿠키 버전을 지원하는 클라이언트와 서버 간에 호환성을 협상하는 용도로 사용한다. 클라이언트가 Version0 쿠키와 Version1 쿠키를 모두 지원하더라도 서버로부터 Version0의 Set-Cookie 헤더를 받으면, 클라이언트는 Version0 Cookie 헤더를 보내야한다. 클라이언트는 해당 서버에 업그레이드 할 수 있다는 의미로 Cookie2: $Version-"1"를 보내야 한다.

 

쿠키와 세션 추척

: 쿠키는 웹 사이트에 수차례 트랜잭션을 만들어내는 사용자를 추적하는 데 사용한다. 

온라인 쇼핑 사이트 과정

  1. 브라우저에 방문하면 일어나는 트랜잭션들의 연속을 보여준다.
  2. 브라우저가해당 사이트의 루트 페이지를 처음 요청한다.
  3. 서버는 클라이언트를 전자상거래 소프트웨어 URL로 리다이렉트 시킨다.
  4. 클라이언트는 리다이렉트 URL로 요청을 보냄
  5. 서버는 응답에 두 개의 세션 쿠키를 기술하고 사용자를 다른 URL로 리다이렉트 시키고 클라이언트는 다시 이 쿠키들을 첨부하여 요청을 보낸다.
  6. 클라이언트는 새로운 URL을 요청을 앞서 받은 두 개의 쿠키와 함께 보낸다.
  7. 서버는 다른 페이지로 리다이렉트 시키고 쿠키 두 개를 더 첨부한다.
  8. 클라이언트는 페이지를 가져오고 총 네 개의 쿠키를 전달한다.
  9. 서버는 콘텐츠를 보낸다.

 

쿠키와 캐싱

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

  • 캐시되지 말아야 할 문서가 있다면 표시하라
  • Set-Cookie 헤더를 캐시하는 것에 유의하라
  • Cookie 헤더를 가지고 있는 요청을 주의하라

 

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

: 개인정보를 다루거나 사용자를 추적하는 기술은 잘못된 의도로 사용될 수 있기 때문에 항상 조심하는 것이 좋다. 쿠키에 대한 부정적인 여론이 많지만 제공하는 개인정보를 누가 받는지 명확히 알고 사이트의 개인정보 정책에만 유의한다면, 쿠키에 관련한 위험성보다 편리함이 더 크다.