본문 바로가기

CS/네트워크

[HTTP] 11. 클라이언트 식별과 쿠키

이 포스팅은 "HTTP-완벽 가이드" 책을 학습하고 정리한 것입니다.

https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=49731592

 

HTTP 완벽 가이드

HTTP 규약이 어떻게 동작하고 웹 기반 애플리케이션을 개발하는 데 어떻게 사용하는지 설명한다. 하지만 이 책은 단순히 HTTP에 대해서만 다루지는 않는다. HTTP가 효율적으로 동작하도록 함께 사

 

 


 

 

 

 

 서버는 클라이언트의 요청을 처리하는 것을 넘어서, 서버와 통신하고 있는 클라이언트를 식별하고 추적해야 할 수도 있다. 이 장에서는 서버가 통신하는 대상을 식별하는 데 사용하는 기술을 알아본다.

 

11.1 개별 접촉

 HTTP는 익명으로 동작하며 상태를 갖지 않는(stateless) 프로토콜이다. 따라서, 웹 서버는 요청을 보낸 사용자를 식별하기 위해 추가적인 정보를 이용해야 한다. 그 방법은 아래와 같다.

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

 위와 같은 방법을 제공하여, 사용자를 식별함으로써 웹 서버는 아래의 기능을 제공할 수 있다.

  • 개인화된 메시지 or 페이지 : 사용자에 특화된 메시지 혹은 페이지 제공
  • 사용자 맞춤 추천 : 사용자 데이터를 토대로 맞춤 추천
  • 저장된 사용자 정보 : 결제 관련 정보들을 유지하여, 사용자가 일일이 입력하지 않도록 하는 편의성 제공
  • 세션 추적 : 사용자의 상태를 유지하여 쇼핑 카트와 같은 기능 제공

 

 

11.2 HTTP 헤더

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

From 헤더

 이상적으로는 사용자 마다 다른 이메일 가지므로, From 헤더를 통해 사용자를 식별할 수 있다. 하지만, 악의적인 서버가 이메일 주소를 모아서 스팸 메일을 발송하는 문제가 있어서 실제로는 From 헤더를 사용하는 브라우저는 많지 않다.

User-Agent 헤더

 사용자가 쓰고 있는 브라우저의 이름과 버전 정보, 어떤 경우에는 운영체제에 대한 정보까지 포함하여 서버에게 알려준다. 이는 특정 브라우저에서 제대로 동작하도록 하는 컨텐츠를 제공하기 위함이다. 사용자를 식별하는데 큰 도움이 되지는 않는다.

Referer 헤더

 사용자가 현재 페이지로 유입하게 한 웹페이지의 URL을 가리킨다. 사용자를 직접적으로 식별할 수는 없지만, 이전에 머물렀던 웹 페이지의 특성을 통해 사용자의 선호를 유추할 수 있다.

 

위 세가지 헤더는 사용자를 식별하는데는 부족하다.

 

 

11.3 클라이언트 IP 주소

 이 방식은 사용자가 확실한 IP 주소를 가지고 있고, 그 주소가 바뀌지 않고, 웹 서버가 요청마다 클라이언트의 IP 주소를 알 수 있다면 문제없이 동작한다. 클라이언트의 IP주소는 보통 HTTP 헤더에 없고, TCP 커넥션에서 클라이언트 IP주소를 알아낼 수 있다. 그러나, 이 정보로 사용자를 항상 식별하는 것을 불가능하다. 그 이유는 아래와 같다.

  • 클라이언트 IP주소는 사용자가 아닌, 사용자의 컴퓨터를 가리킨다. 여러 사용자가 한 컴퓨터에서 사용한다면, 서버는 클라이언트 IP주소를 이용하여 사용자를 식별할 수 없다.
  • ISP(인터넷 서비스 제공자)는 사용자가 로그인하면 동적으로 IP 주소를 할당한다. IP 주소는 변할 수 있다.
  • 보안 강화를 위해 클라이언트가 NAT 뒤에서 동작할 수 있다. 이 경우, NAT 뒤에 존재하는 LAN에 클라이언트들은 동일한 게이트웨이를 통해 WAN으로 나가므로, 동일한 IP 주소를 가지고 나가게 된다.
  • 원 서버와 클라이언트 사이에 프록시가 존재할 경우, 프록시가 원 서버에게 클라이언트 IP 주소를 전달해줘야 한다.

 

11.4 사용자 로그인

사용자 로그인은 아래 포스팅을 참조한다.

 

[HTTP] 12. 기본 인증

이 포스팅은 "HTTP-완벽 가이드" 책을 학습하고 정리한 것입니다. https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=49731592 HTTP 완벽 가이드 HTTP 규약이 어떻게 동작하고 웹 기반 애플리케이션을 개발하는 데

w-f-m.tistory.com

 

 

11.5 뚱뚱한 URL

사용자의 상태 정보를 포함하고 있는 URL을 뚱뚱한 URL이라고 한다. 형태는 아래와 같다.

 

 위의 굵은 글씨로 표현된 부분이 사용자를 식별하기 위한 정보이다. 해당 정보를 통해 서버는 사용자를 식별한다. 그러나 치명적인 단점을 가지고 있으며, 아래와 같다.

  • 못생긴 URL : 난잡해 보이는 URL은 사용자에게 혼란을 준다.
  • 공유하지 못하는 URL : 뚱뚱한 URL이 다른 악의적인 사용자에게 전달될 경우, 사용자의 개인 정보가 유출될 수 있다.
  • 캐시를 사용할 수 없음 : 사용자마다 요청하는 URL이 다르기 때문에, 캐시를 적용할 수 없다.
  • 서버 부하 가중 : 서버는 사용자마다 HTML 문서를 새롭게 만들어야 한다.(href 태그에 사용자 식별을 위함 링크로 변경해야 함.)

 

11.6 쿠키

 (이 챕터의 가장 핵심이다.) 쿠키는 사용자를 식별하고 세션을 유지하는 방식 중에서 현재까지 가장 널리 사용하는 방식이다. 쿠키는 캐시와 충돌할 수 있어서, 대부분의 캐시나 브라우저는 쿠키에 있는 내용물을 캐싱하지 않는다.

11.6.1 쿠키의 타입

 쿠키는 크게 세션 쿠키(session cookie)와 지속 쿠키(persistent cookie) 두 가지 타입으로 나눌 수 있다. 두 타입을 나누는 기준은 ‘파기되는 시점’ 이다. 세션 쿠키는 사용자가 사이트를 탐색할 때, 관련한 설정과 선호 사항들을 저장하는 임시 쿠키이다. 브라우저를 닫으면 세션 쿠키는 지워진다.

 

 지속 쿠키는 디스크에 저장되어, 브라우저를 닫거나 컴퓨터를 재시작하더라도 남아있다. 지속 쿠키는 주기적으로 방문하는 사이트의 설정 정보나 사용자 로그인 정보를 유지하기 위해 사용된다.

 만약, 쿠키에 Discard 파라미터가 설정되있거나, Expiresd 혹은 Max-Age 파라미터가 없다면, 해당 쿠키는 세션쿠키가 된다.

 

 

11.6.2 쿠키는 어떻게 동작하는가

 쿠키는 서버가 사용자에게 “안녕, 내 이름은 *** 사용자야. ~~”라고 적어서 붙이는 스티커와 같다(서버가 사용자에게 스티커를 붙이는 것임). 처음 사용자가 웹 사이트에 방문하면, 서버는 사용자의 정보를 갖고 있지 않다. 이후 사용자가 다시 돌아왔을 때, 식별하기 위해, 유일한 값을 쿠키에 할당한다. 쿠키는 [Key=Value] 형태의 리스트로 구성된다. 해당 리스트는 Set-Cookie or Set-Cookie2 같은 HTTp 응답 헤더에 기술되어 사용자에게 전달된다.

 

 브라우저는 쿠키 컨텐츠를 브라우저 쿠키 데이터베이스에 저장한다. 이후 사용자가 같은 웹 사이트를 방문하면, 할당했던 쿠키를 Cookie 요청 헤더에 기술하여 서버에 전달한다.

 

 

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

 쿠키의 기본적인 발상은 브라우저가 서버 관련 정보를 저장하고, 사용자가 해당 서버에 접근할 때마다 그 정보를 함께 전달하는 것이다. 브라우저는 쿠키 정보를 저장할 책임이 있는데, 이 시스템을 “클라이언트 측 상태”라고 한다. 공식적인 이름은 “HTTP 상태 관리 체계(HTTP State Management Mechanism)”이다.

 

(F12 → Application → Storage → Cookie)

아래 이미지는 구글 크롬에서 확인한 네이버 웹사이트 접속 시 쿠키 정보이다.

  • Name : 쿠키의 이름
  • Value : 쿠키의 값
  • Domain : 쿠키의 도메인
  • Path : 쿠키와 관련된 도메인에 있는 경로
  • Expires / Max-Age : 쿠키의 시점을 알려준다. Session은 지속 쿠키가 아닌, 브라우저 종료 시 사라지는 세션 쿠키임을 의미한다.
  • Size : 쿠키의 크기
  • HttpOnly : 클라이언트 측 스크립트에서 쿠키에 액세스할 수 없는 경우, true입니다.
  • Secure : 쿠키에 보안설정이 적용된 경우 True이다.(ex. https)
  • SameSite : SameSite 정책에 대한 쿠키의 정보
  • Partition Key : The partition key for reading or modifying cookies with the Partitioned attribute.
 

chrome.cookies  |  API  |  Chrome for Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English chrome.cookies 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 설명 chrome.cookies API를 사용하

developer.chrome.com

 

 

 

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

 브라우저는 수백 혹은 수천개의 쿠키들을 내부 쿠키 저장소에서 관리한다. 각 쿠키들을 웹 사이트들에 매핑되있으며, 브라우저는 웹 사이트에 접속할 때, 해당 사이트에 매핑된 쿠키들만을 요청 헤더에 포함하여 전달한다. 이러한 이유는 아래와 같다.

  • 관련 없는 모든 쿠키를 전달하는 것은 성능을 저하시킨다.
  • A라는 사이트에서 사용하는 쿠키는 B라는 사이트에서 쓸모없는 값일 것이다. 왜냐하면, 각 사이트 별로 쿠키의 이름/값 포멧이 다르기 때문이다.
  • 관련 없는 쿠키까지 모두 전달하는 것은 보안 유출의 이슈를 야기할 수 있다.

 웹 사이트들을 웹 광고를 매니징하기 위해 서드파티 벤더사와 계약을 맺곤 한다. 이때 광고와 관련된 쿠키들을 ‘지속 쿠키’로서 다른 사이트에 옮겨질때도 동일하게 쿠키 헤더에 포함되어 전달될 수 있다. 서버가 서드파티 쿠키를 관리하는 방법은 아래와 같다.

 

 

11.6.4.1 Coocke Domain attribute

 쿠키를 생성하는 서버는 Set-Cookie 응답 헤더에 Domain attribute를 사용하여, 어떤 사이트에 해당 쿠키가 전달되면 되는지 컨트롤할 수 있다. 예를 들어 HTTP 응답 헤더에 아래와 같은 헤더를 포함한다고 가정하자.

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

 

 사용자가 “.airtravelbargains.com”라는 도메인을 포함한 URL로 HTTP 요청을 보낼 경우, 브라우저는 아래의 쿠키 헤더를 포함한 요청을 전송할 것이다.

Cookie: user="mary17"

 

 

11.6.4.2 Cookie Path attribute

앞에서 확인한 Domain attribute에 더 디테일하게 ‘경로 지정’도 포함하여 컨트롤할 수 있다. 아래와 같은 헤더를 응답 헤더에 포함했다고 가정하자.

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

클라이언트가 “www.airtravelbargains.com/special.html"라는 URL에 요청을 전달할 때는, 아래와 같은 헤더를 요청 헤더에 포함할 것이다.

Cookie: user="mary17"

반면, “www.airtravelbargains.com**/autos/**cheapo/index.html"이라는 URL에 요청을 전달할 때는, 아래와 같은 헤더를 요청 헤더에 포함할 것이다.

Cookie: user="mary17"
Cookie: pref=compact

 

 

 

광고 서드파티 쿠키

 임의의 티스토리 블로그에 접속하여 광고 베너를 클릭하면, 광고 서드파티 쿠키가 광고 베너 URL을 포함한, HTTP 요청에 포함되어 전송된다.

 아래 이미지는 티스토리 블로그와 관련한 도메인에 매핑된, ‘광고 서드파티 쿠키’에 해당하는 쿠키이다.

아래 캡처 이미지는, 구글 ad 클릭시 googleads.g.doubleclick.net 도메인으로 전송되는 HTTP 요청의 쿠키(DSID = ~~)이다. 이를 통해, 웹 광고와 관련하여 실제로 쿠키를 활용함을 확인하였다.

 

 

 

11.6.5 쿠키 구성요소

(현재 사용중인 쿠키 버전과 책에서 언급한 쿠키 버전의 차이가 있어, 이번 챕터는 NHN 기술 블로그를 참조하여 작성함)

 

HTTP 쿠키와 톰캣 버전별 이슈 : NHN Cloud Meetup

HTTP 쿠키와 톰캣 버전별 이슈

meetup.nhncloud.com

쿠키는 버전0과 버전1로 나눠진다.

  • version 0 : Netscape cookie standard
  • version 1 : (책에서는 RFC 2965(이전에는 RFC 2109) 명세라고 함. 현 시점, RFC 2965는 폐기됨) RFC 6265

각각의 버전 별 쿠키의 대표적인 속성은 아래와 같다.

  • Netscape 쿠키 : Name, Value, Expires, Domain, Path, Secure
  • RFC 2109 : Name, Value, Comment, Domain, Max-Age, Path, Secure, Version
  • RFC 6265 : Name, Value, Expires, Domain, Max-Age, Path, Secure, HttpOnly

 

 

11.6.8 쿠키와 세션 추적

 

크롬에서 서드 파티 쿠키를 폐기하기 위한 다음 단계

웹 상에서 개인 정보 보호를 개선하는 작업은 절대 끝이 없습니다. 이에 크롬(Chrome)에서는 이용자들의 데이터를 보호하고 통제권을 강화할 수 있는 새로운 기능들 에 계속해서 투자하고 있습니

korea.googleblog.com

(2024년 1월 16일 현 시점, 구글은 크롬에서 서드파티 쿠키 추적을 당해년도 9월부터 금지하겠다는 발표를 내렸다)

 

‘쿠키’ 이제 끊습니다?...광고업계가 후덜덜 떠는 이유 [뉴스 쉽게보기] - 매일경제

올해는 온라인 광고 시장에 아주 중요한 한 해가 될 것으로 보여요. 세계 온라인 광고업계를 꽉 잡고 있는 구글이 ‘맞춤형 광고’에 사용되는 일부 데이터 수집을 중단할 예정이기 때문이에요.

www.mk.co.kr

(매일 경제 뉴스)

 다만 이 챕터에서 말하는 세션 추적은 위 포스팅과는 결이 다르다. 쿠키의 종류는 퍼스트파티와 서드파티 쿠키로 나눠질 수 있다. 퍼스트파티는 웹 사이트의 서버와 클라이언트가 1대1로 맺는 관계에서 주고받는 쿠키로, 쿠키에 사용자의 토큰값을 넣어, 사용자를 식별하는 등에 활용된다. 서드파티 쿠키는 제3자에게 제공되는 쿠키로서, A라는 사이트에서 활동한 내역이 B라는 사이트로 이동했을 때, 그동안의 사용 기록으로 맞춤형 광고를 제공하는 기능으로 활용되었다. 현재 금지하고자 하는 쿠키는 이러한 서드파티 쿠키이다.

 

 

 책에서는 아마존 웹 사이트에서의 장바구니 기능을 세션 추적 예시로 활용하고 있다.

필자는 아마존이 아닌, 알라딘 웹 사이트에서의 장바구니 기능을 예제로 활용하고자 한다.

 

 

1. 장바구니 담기 버튼 클릭

 

 알라딘에서 장바구니에 담을 책의 이름은 “내가 가진 것을 ~~”이라는 제목의 책이다.

 

 위의 ‘장바구니 담기’ 버튼을 클릭하면, 브라우저는 알라딘 웹 사이트에 아래와 같은 HTTP 요청을 전달하고, 알라딘 웹 사이트는 Set-cookie 응답 헤더를 통해 쿠키를 브라우저에 저장시킨다.

 

2. 서버의 Set-Cookie 헤더를 포함한 HTTP 응답

 브라우저는 quickbuycheck라는 value를 method 변수에 담아 전송(맨 위 요청)하는데,

해당 요청에 대한 HTTP 응답의 쿠키 헤더(Set-Cookie)는 아래와 같다.

 

 위 내용을 보면 ‘AladdingUser’ , ‘AladdingSession’ 이라는 쿠키를 저장시키는 것을 알 수 있다. 필자도 정확히 어떤 세션 ID가 서버 내의 장바구니 데이터와 매핑되는지는 모르기 때문에, 일단 전부 캡처하였다.

 

3. 장바구니 페이지 들어가기

 

 장바구니 페이지를 들어가보면 위와 같은 페이지를 응답 받는다. 여기서 실험해볼 것이 있다. 장바구니 페이지 요청을 전달할 때, 브라우저는 처음 Set-Cookie로 전달 받은 쿠키들을 HTTP 요청에 함께 실어서 전송한다. (아래 이미지는 위 페이지 HTTP 요청의 Header이다)

 

 만약, 알라딘에서 쿠키에 있는 값들을 토대로 장바구니 기능을 구현한 것이라면, 브라우저가 아닌 환경에서 HTTP 요청(동일한 쿠키 포함)을 전달했을 때, 위 장바구니 페이지가 동일하게 응답 되어야한다.

 

 필자는 이 실험을 위해 인텔리제이의 ‘HTTP Request’ 기능을 사용하였다.

인텔리제이에서 전송한 요청 메시지는 아래와 같다.

GET https://www.aladin.co.kr/shop/wbasket.aspx
Cookie:AladdinUser=UID=1084595315&SID=fIRa6p1wG19%2fvqnW8Ndgpw%3d%3d; 
				AladdinSession=UID=1084595315&SID=fIRa6p1wG19%2fvqnW8Ndgpw%3d%3d; 
				AladdinUS=Z8GkqCH1PRZ%2f3tXM%2fZCLZQ%3d%3d&USA=0;

 

 필자의 예상과 동일하게 동일한 장바구니 페이지를 응답하였다. 아래 이미지는 응답 내용이다. 이를 통해 실제 운영되는 서비스에서 장바구니 기능을 구현하기 위해 쿠키를 활용한다는 것을 검증하였다.

 

 

 

11.6.9 쿠키와 캐싱

쿠키 트랜잭션과 관련된 문서를 캐싱하는 것은 주의해야 한다. 이전 사용자의 쿠키가 다른 사용자에게 할당돼버리거나, 누군가의 개인 정보가 다른 이에게 노출되는 최악의 상황이 일어날 수도 있다. 이에 정해진 규칙은 없지만, 권장되는 원칙은 아래와 같다.

캐시되지 말아야 할 문서가 있다면 표시하라

만약 문서가 Set-Cookie 헤더를 제외하고 캐시를 해도 될 경우라면 그 문서에 명시적으로 Cache-Control: no-cache=”Set-Cookie”를 기술해서 명확히 표시한다.

Set-Cookie 헤더를 캐시 하는 것에 유의하라

  • 같은 Set-Cookie 헤더를 여러 사용자에게 보내게 되면, 사용자 추적에 실패할 수 있다.
  • 어떤 캐시는 응답하기 전에, Set-Cookie 헤더를 제거하기 때문에, 그 캐시 데이터를 받는 클라이언트는 Set-Cookie 헤더 정보가 없는 데이터를 받게 되어 문제가 발생할 수 있다. 이 경우, 원 서버에서 “Cache-Control: must-revalidate, max-age=0” 헤더를 캐시된 문서에 추가하여, 캐시 재검사가 되도록 할 수 있다.

Cookie 헤더를 가지고 있는 요청을 주의하라

Cookie 헤더를 포함한 요청은 개인정보를 포함할 수 있다는 힌트이기 때문에, 개인정보가 캐시되지 않도록 주의해야 한다.

'CS > 네트워크' 카테고리의 다른 글

[HTTP] 16. 국제화  (0) 2024.01.17
[HTTP] 15. 엔터티와 인코딩  (0) 2024.01.16
[HTTP] 14. 보안 HTTP  (2) 2024.01.10
[HTTP] 12. 기본 인증  (0) 2024.01.09
[HTTP] 10. HTTP/2.0  (2) 2024.01.08