웹서버는 다른 수천개의 클라이언트들과 동시에 통신을 합니다. 이 서버들은 클라이언트로부터 받는 모든 요청을 처리하는 것뿐만 아니라, 서버와 통신하고 있는 클라이언트를 추적해야 할 수도 있습니다.
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 예시
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 같은 확장 헤더를 추가하여, 이문제를 해결하려 했습니다. 하지만 모든 프락시가 이런 식으로 동작하진 않습니다.
사용자 로그인 (Authorization) 🔑
IP 주소로 사용자를 식별하려는 수동적인 방식보다, 웹 서버는 사용자 이름과 비밀번호로 인증(로그인)할 것을 요구해서 사용자에게 명시적으로 식별 요청을 할 수 있습니다.
HTTP는 WWW-Authenticate와 Authorization 헤더를 사용해 웹 사이트에 사용자 이름을 전달하는 자체적인 체계를 가지고 있습니다.
한번 로그인하면, 브라우저는 사이트로 보내는 모든 요청에 이 로그인 정보를 함께 보내므로 웹서버는 로그인 정보를 항상 확인 할수 있습니다.
서버에서 사용자가 사이트에 접근하기 전에 로그인을 시키고자 한다면 HTTP 401 Login Required 응답 코드를 브라우저에 보낼 수 있습니다.
뚱뚱한 URL 🍔
사용자의 상태 정보를 포함하고 있는 URL을 뚱뚱한 URL이라고 부릅니다.
웹서버와 통신하는 독립적인 HTTP 트랜잭션을 하나의 '세션' 혹은 '방문'으로 묶는 용도로 뚱뚱한 URL을 사용할 수 있습니다.
아래는 Amazon.com에서 사용자에게 식별번호를 할당해 추적하는 예입니다. 20658007011 라는 특정 값이 URL에 계속 붙어 사용자를 추적하는것을 확인 할수 있습니다.
이러한 방식은 여러 문제가 있는데, 아래와 같습니다.
못생긴 URL
브라우저에 보이는 뚱뚱한 url은 사용자들에게 혼란을 줍니다.
공유하지 못하는 URL
url에 세션에 대한 상태 정보를 포함하기 때문에, 개인정보를 본의아니게 공유하게 됩니다.
캐시를 사용할 수 없음
url로 만드는것은, url이 달라지기 때문에 기존 캐시에 접근할 수 없다는 것을 말합니다.
서버 부하 가중
서버는 뚱뚱한 URL에 해당하는 페이지를 그려야 합니다.
이탈
URL 세션에서 이탈하면, 지금까지의 진척상황들이 초기화 되고 다시 처음부터 시작되어야 할 것입니다.
세션간 지속성의 부재
url을 북마킹 하지 않는 이상, 로그아웃하면 모든 정보를 잃습니다.
쿠키 🍪
쿠키는 사용자를 식별하고 세션을 유지하는 방식 중에서 현재까지 가장 널리 사용하는 방식입니다.
쿠키는 새로운 HTTP 헤더를 정의합니다.
쿠키는 캐시와 충돌할 수 있어, 대부분의 캐시나 브라우저는 쿠키에 있는 내용물을 캐싱하지 않습니다.
쿠키의 타입
세션 쿠키
사용자가 사이트를 탐색할때, 관련한 설정과 선호 사항들을 저장하는 임시쿠키
사용자가 브라우저를 닫으면 삭제
지속 쿠키
디스크에 저장되어, 브라우저를 닫거나 컴퓨터를 재시작하더라도 남아있음.
사용자가 주기적으로 방문하는 사이트에 대한 설정 정보나 로그인 이름을 유지하려고 사용
다른점
파기되는 시점
쿠키는 Discard 파라미터가 설정되어 있거나, 파기되기까지 남은 시간을 가리키는 Expires 혹은 Max-Age 파라미터가 없으면 세션 쿠키가 됩니다.
쿠키의 동작 방식
A) 처음 사용자가 웹 사이트를 방문하면 서버는 사용자에 대해서 아무것도 모릅니다.
B) 서버는 사용자를 식별하기 위한 값을 쿠키에 할당합니다. 쿠키는 이름=값 형태의 리스트를 가지고, 그 리스트는 Set-Cookie 혹은 Set-Cookie2 같은 HTTP 응답헤더에 기술해 사용자에게 전달합니다.
C) 브라우저는 서버로 온 헤더에 있는 쿠키 콘텐츠를 브라우저 쿠키 데이터베이스에 저장하고, 브라우저는 추후 요청에 서버가 이 사용자에게 할당했던 쿠키를 cookie 요청헤더에 기술해 전송합니다.
사이트마다 각기 다른 쿠키들
브라우저는 수백, 수천개의 쿠키를 가질 수 있지만, 브라우저가 쿠키 전부를 모든 사이트에 보내지 않는데, 그이유는 아래와 같습니다.
쿠키를 모두 전달하면 성능이 크게 저하됩니다.
쿠키들은 대부분 서버 특화된 이름/값 쌍을 포함하고 있기 때문에, 대부분 사이트에서는 인식하지 않는 무의미한 값입니다.
모든 사이트에 쿠키 전체를 전달하는 것은, 특정사이트에서 제공한 정보를 신뢰하지 않는 사이트에 가져갈수 있으므로 잠재적인 개인정보 문제를 일으킬 수 있습니다.
쿠키 Domain 속성
서버는 쿠키를 생성할 때, Domain 속성을 기술해 어떤 사이트가 그 쿠키를 읽을 수 있는지 제어할 수 있습니다.
아래 예는, 브라우저가 user="ideveloper"라는 쿠키를 .ideveloper2.dev 도메인을 가지고 있는 모든 사이트에 전달한다는 의미입니다.