# 11. Client Identification and Cookies

웹 서버는 서로 다른 수천개의 클라이언트와 동시에 통신한다.

이 서버들은 익명의 클라이언트로부터 받는 모든 요청을 처리할 뿐만 아니라, 서버와 통신하고있는 클라이언트를 추적해야할 수도 있다.

서버가 통신하는 대상을 식별하는데 사용하는 기술을 알아본다.

## 1) 개별 접촉

```
**Stateless(무상태)**:
  - 서버가 클라이언트의 상태를 보존하지 않는다.
  - 연결자체에 대한 정보를 가지지 않고, 매 요청은 일회성이고 독립적으로 처리된다.
  - 장점: 서버 확장성이 좋다. (scale-out)
  - 단점: 클라이언트가 추가 데이터를 전송해야한다.
```

HTTP 는 익명으로 사용하고, 상태가없고(stateless), 요청과 응답으로 통신하는 프로토콜이다.

웹 서버는 요청을 보낸 사용자를 식별하거나, 방문자가 보낸 연속적인 요청을 추적하기위해 약간의 정보를 이용할 수 있다. 현대 웹 사이트들은 개인화 서비스를 제공하고 싶어한다. 네트워크로 연결된 사용자들에 대해 더 많이 알고 싶고, 검색을 기록하고 싶다. 여러가지 방식으로 **개인화**시켜서 사용자에게 제공한다.

* **개별 인사**: 개인에게 맞춰져 있는것 처럼 느끼도록 사용자에게 특화된 환영메세지나 페이지 내용을 만든다.
* **사용자 맞춤 추천**: 고객의 흥미를 학습하고, 좋아할것을 예측해서 추천. 혹은 생일, 중요한날 특별제품 제시.
* **저장된 사용자 정보:** 한번 식별을 하고 나면, 다음 이용을 더 편하게 하도록 사용자정보를 사용할수있다.
* **세션 추적**: HTTP 트랜잭션은 무상태지만, 상태를 유지하도록 각 사용자에게서 오는 HTTP 트랜잭션을 식별.

HTTP 가 사용자를 식별하는데 사용하는 기술을 정리해보자.

## 2) HTTP 헤더

```
* 사용자에 정보를 전달하는 일반적인 7가지 HTTP 요청헤더
    - From: 사용자 이메일 주소   
  - User-Agent: 사용자 브라우저
  - Referer: 사용자가 현재 링크를 타고온 근원 페이지 

  - Authorization: 사용자 이름과 비밀번호
  - Client-ip: 클라이언트의 IP 주소
  - X-Forwarded-For: 클라이언트의 IP 주소
  - Cookie: 서버가 생성한 ID 라벨
```

*   **From**: (이상적으로는) 각 사용자가 모두 다른 이메일 주소를 가지니까 사용자를 식별할 수 있음.

    단, 악의적인 서버가 이메일 주소를 모아 스팸메일을 발송할 수 있어서 From헤더를 보내는 브라우저는 적다.
*   **User-Agent헤더**: 브라우저 이름, 버전, OS 정보를 포함해서 서버에 보내지만, 사용자 식별에는 큰 도움 X

    (특정 브라우저에서 제대로 동작하도록 속성에 맞춰 콘텐츠 최적화 가능)
*   **Referer**: 이 헤더만으로 사용자를 식별할 수는 없지만, 이전에 어떤 페이지를 방문했는지 알려준다.

    (취향파악, 웹사용행태를 파악하는데 유용하다.)

## 3) 클라이언트 IP 주소

초기에 사용자 식별을 위해 클라이언트 IP 주소를 사용하려 했다.

사용자는 확실한 IP 주소를 가지고있고, 그 주소가 좀처럼(혹은 절대) 바뀌지 않고, 웹 서버가 요청마다 클라이언트의 IP 주소를 알수 있을 때는 문제없이 동작한다.

단, 몇가지 **약점**을 가지고 있다.

* 클라이언트 IP 주소는 사용자가 아닌, 컴퓨터를 가리킨다. (한 컴퓨터에 여러 사용자가 사용하면?)
* ISP는 동적으로 IP 주소를 할당해준다. 로그인 시간에 따라 사용자는 매번 다른 주소를 받는다.
* 보안을 강화하면서 NAT(network address translation) 방화벽을 통해 인터넷을 사용한다. 실제 IP주소는 뒤로 숨기고, 내부에서 사용하는 하나의 IP주소(&포트번호)로 변환한다.
* 웹서버는 클라이언트의 IP주소대신 프록시 서버의 IP주소를 본다. 일부 프락시는 원본 IP주소를 보존하기위해 Client-IP, X-Forwarded-For로 해결하려 했으나 모든 프락시가 이렇게 동작하지는 않는다.

## 4) 사용자 로그인

IP 주소로 사용자를 식별하는 수동적인 방식보다, 웹서버는 사용자 이름과 비밀번호 인증(로그인)할것을 요구해서 사용자에게 **명시적으로 식별 요청**을 할 수 있다.

웹사이트 로그인이 쉽도록 `WWW-Authenticate` 와 `Authorization` 헤더를 사용해 웹 사이트에 사용자 이름을 전달하는 자체적인 체계를 가지고 있다.

사용자를 인증 받으면, 이 시점 이후부터는 서버로부터 사용자 식별 정보 요청에 대해 자동으로 이름과 비밀번호를 포함해서 요청하지 않을 때에도 전달한다. 한번 로그인하면 브라우저는 요청마다 해당 식별정보 토큰을 `Authorization` 헤더에 담아 서버로 전송해서 한 세션이 진행되는 내내 그 사용자에 대한 식별을 유지한다.

하지만, 사이트를 옮겨다닐대마다 각 사이트에 로그인을 해야한다거나, 각 사이트별로 다른 아이디와 비밀번호를 기억해야하고, 내가 좋아하는 아이디를 누군가 먼저 선점했을 수도 있고, 사이트별로 조합 규칙을 두어 내가 사용하는 비밀번호와 다를 수도 있다. 그래서 웹사이트 로그인은 귀찮은 일이 될 수 있다.

## 5) 뚱뚱한 URL

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

사용자에게 할당된 식별번호 (예: 002-1145265-8016838) 를 각 URL 뒤에 붙여 사용자를 추적한다.

웹 서버와 통신하는 독립적인 HTTP 트랜잭션을 하나의 '세션' 혹은 '방문'으로 묶는 용도로 뚱뚱한 url을 사용할 수 있다. 하지만, 이 기술에는 여러 문제가 있다.

* **못생긴 URL:** 새로운 사용자에게 혼란을 줄 수 있다.
* **공유하지 못하는 URL:** 특정 사용자에 대한 상태정보를 포함하므로 누적된 개인정보를 공유하게 됨
* **캐시를 사용할 수 없음**: URL이 달라지기 때문에 기존 캐시에 접근 불가능
* **서버 부하 가중**: 뚱뚱한 URL에 대한 HTML 페이지를 다시 그려야함.
* **이탈**: 서비스를 사용하는 동안, 사전에 세션 정보가 추가된 링크만 사용해야 된다. 해당 링크를 이탈하면 진척상황이 초기화되고 처음부터 다시 시작해야한다.(장바구니 넣었던거 사라지거나 등등)
* **세션간 지속성 부재**: 특정 뚱뚱한 URL을 북마킹하지 않는 이상, 로그아웃시 모든 정보를 잃게됨.

## 6) 쿠키

쿠키는 사용자를 식별하고 세션을 유지하는 방식중 현재까지 가장 널리 사용되는 방식이다.

앞의 기술들이 가진 문제점을 겪지는 않지만, 쿠키만으로 해결하기 힘들 땐 앞선 기술들을 함께 사용하기도 한다.

쿠키는 캐시와 충돌할 수 있어서, 대부분의 캐시나 브라우저는 쿠키에 있는 내용물을 캐싱하지 않는다.

### ① 쿠키의 타입

* 세션 쿠키(session cookie)
  * 사용자가 사이트 탐색시 관련 설정과 선호 사항을 저장하는 임시 쿠키이다.
  * 사용자가 브라우저를 닫으면 삭제된다.
* 지속 쿠키(persistent cookie)
  * 디스크에 저장되어 브라우저를 닫거나 컴퓨터를 재시작하더라도 남아있다.
  * 사용자가 주기적으로 방문하는 사이트에 대한 설정정보나 로그인 이름을 유지하기위해 사용한다.

### ② 쿠키는 어떻게 동작할까?

* 쿠키는 서버가 사용자에게 붙이는 **스티커** 같다.
* 사용자가 웹사이트에 방문하면, 웹사이트는 서버가 사용자에게 붙인 모든 스티커를 읽을 수 있다.
* 동작 순서
  * 처음 사용자가 웹사이트방문시 웹서버는 사용자에 대해 아무것도 모른다.
  * 사용자가 다시 돌아오면 서버는 해당 사용자를 식별하기 위한 값을 쿠키에 할당한다.
    * 쿠키는 임의의 이름=값 형태의 리스트를 가지고
    * `set-Cookie`, `set-Cookie2` 같은 HTTP 응답헤더에 기술되서 사용자에 전달한다.
    * 서버는 이 쿠키값으로 DB 에서 사용자의 정보를 찾는데 사용이 가능하다.
  * 브라우저는 서버로부터 온 헤더에 있는 쿠키 콘텐츠를 브라우저 쿠키 데이터베이스에 저장한다.
    * 사용자가 미래에 같은 사이트를 방문하면 서버가 사용자에게 할당한 쿠키를 요청헤더에 전달.

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

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

각 브라우저 별로 다른 방식으로 쿠키를 저장하고, 구글 크롬은 Cookies라는 SQLite 파일에 쿠키를 저장.

*   **구글 크롬 쿠키 확인하기**

    \[개발자도구] - \[Application 탭] - \[좌측 Storage탭] - \[Cookies]

    ![01](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F6cf0c380-7b63-482e-aec2-ea384bd1eacf%2F_2021-06-14__4.34.40.png?table=block\&id=95b1db38-33c0-4a1f-8f15-f8648222240b\&spaceId=da06fe4c-dbc0-451e-a09d-8fe561a808ae\&width=2730\&userId=\&cache=v2)
* 주요 필드 중
  * name: 쿠키 이름
  * value: 쿠키 값
  * HttpOnly: XSS 공격방지 (javaScript에서 접근 불가능. HTTP전송에만 사용)
  * Secure: 쿠키는 HTTP, HTTPs 구분없이 전송하고, secure적용시 https인 경우만 전송
  *   samesite : 서드파티 쿠키의 보안 문제를 해결하기 위해 만들어진 기술

      참조: [https://seob.dev/posts/브라우저-쿠키와-SameSite-속성/](https://seob.dev/posts/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%BF%A0%ED%82%A4%EC%99%80-SameSite-%EC%86%8D%EC%84%B1/)

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

브라우저는 수백\~수천개의 쿠키를 가지고 있을수 있지만, 그렇다고 브라우저가 쿠키 전부를 모든 사이트에 보내지는 않는다. 브라우저는 보통 각 사이트에 1\~3개의 쿠키만을 보낸다.

이유

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

보통 브라우저는 쿠키를 생성한 서버에게만 쿠키에 담긴 정보를 전달한다.

쿠키는 일종의 상태 정보라고 할수 있고, 서버가 생성해서 클라이언트에 전달하고 클라이언트는 그 쿠키를 유효한 사이트에만 다시 전달하고 관리한다.

(5\~7) 책 참조

### ⑧ 쿠키와 세션 추적

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

(그림/설명 참조)

### ⑨ 쿠키와 캐싱

쿠키 트랜잭션과 관련된 문서를 캐싱하는 것은 주의해야한다.

이전 사용자의 쿠키가 다른 사용자에게 할당 되버리거나, 누군가의 개인정보가 다른이에게 노출되는 최악의 상황이 일어날 수도 있다.

캐시를 다루는 기본 원칙

* 캐시되지 말아야할 문서가 있다면 표시하라.
  * 문서를 캐시하면 될지 안될지는 문서의 소유자가 더 잘 안다.
* Set-Cookie 헤더를 캐시하는 것에 유의하라.
* Cookie 헤더를 가지고 있는 요청을 주의하라.
*   **세션 쿠키 차이점 \[참고]**

    ![02](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fb85ab2e5-ee5e-417b-8cc0-4335b46695c7%2FUntitled.png?table=block\&id=d5d13507-addb-40dc-9d97-0135ace35a4a\&spaceId=da06fe4c-dbc0-451e-a09d-8fe561a808ae\&width=1760\&userId=\&cache=v2)

    * [https://hahahoho5915.tistory.com/32](https://hahahoho5915.tistory.com/32)
