태그
요약프론트엔드Web
최종 편집
Dec 30, 2022 2:32 AM
발행일
November 5, 2021
쿠키란 무엇인가?
- 쿠키는 세션 관리, 개인화, 유저 행동 추적 등에 쓰인다.
- 이전에는 쿠키가 모든 클라이언트 정보 저장을 담당하기도 했지만, 쿠키는 해당 도메인의 서버에 보내는 모든 요청에 함께 가기 때문에 성능 이슈가 있으며, 도메인별로 갯수 및 용량 제한이 있다(대개 20개, 4kb).
- 요즘은 보통 Web Storage APIs를 사용한다. 이들은 5MB까지도 가능하다.
쿠키 접근하고 할당하기
- 클라이언트(브라우저)에서는
document.cookie
로 접근하고 할당할 수 있다. document.cookie = "hello=world; domain=example.com; Secure";
- 위와 같이 한다고 쿠키 값이 완전히 덮어써지는 건 아니다. 같은 키의 값이 있으면 업데이트해줄 뿐.
- 헷갈리므로 js-cookie 같은 패키지를 쓰는 게 좋다. TypeScript 지원도 된다.
- 서버(Node.js)에서는 HTTP 요청의 request header로 접근하고, response header로 수정할 수 있다.
- 브라우저가 보낸 쿠키는 요청 헤더에
cookie
라는 key로, 값은key=value;
형태로 들어있다. - 쿠키를 브라우저에 원하는 값으로 할당할 때는 response 헤더에
Set-Cookie
헤더를 쓰면 된다. - 클라이언트의 경우와 마찬가지로, cookie-parser 같은 미들웨어를 쓰면 더 편하다. TypeScript 지원도 된다.
http.createServer(function (request, response) {
var cookies = request.headers.cookie;
// "cookie1=value1; cookie2=value2"
...
}).listen(8124);
response.writeHead(200, {
'Set-Cookie': 'mycookie=test; domain=example.com; Secure'
});
쿠키의 속성들
- Domain: 브라우저에게 어떤 호스트가 쿠키 값을 읽을 수 있는지 지정해준다. 없으면 쿠키를 Set한, 동일 호스트만 읽을 수 있으며, 같은 도메인을 가진 서버 API를 호출할 때만 쿠키가 함께 움직인다.
- 물론 이게 있다고 아무 도메인에서나 쿠키 값을 읽을 수 있는 건 아니다. 단지 서브도메인에게 쿠키 값을 허용할 것인지 정도의 의미가 있다.
- 예를 들어 내 현재 도메인이
abc.xyz.com
인데Domain
속성을 지정하지 않았다면 정확히 이 도메인에서만 쿠키를 읽을 수 있지만,Domain=xyz.com
을 설정해두면 다른def.xyz.com
도 읽을 수 있다. - 아무 값이나 여기에 넣을 수 있는 것은 아니다.
.com
같은 TLD,.co.uk
같은 유사 TLD로 세팅된Domain=
은 대부분의 브라우저에서 무시된다. - 과거에는 이 목록이 각 브라우저 벤더에서 내부적으로 관리해서 inconsistency가 있었으나, 요즘은 Mozilar에서 Public Suffix List 프로젝트를 발족해서 이걸 전체 벤더가 공유한다. 이 목록에는
github.io
나vercel.app
같은 서비스도 들어있다. - Path: Domain과 유사하게, 여기 명시된 하위 경로에서만 쿠키 접근이 가능하게 한다. 예를 들어
Path=/store
가 정의된 쿠키는/store
,/store/cart
등에서만 접근 가능하다. - Expires: 쿠키가 언제 이후로 폭파될지 정의한다. 일정 주기로 광고를 보여주는 등의 유즈케이스에서 유용하다. 과거 시각으로 설정함으로써 쿠키를 삭제할 때도 쓸 수 있다(쿠키를 삭제하는 방법으로 스펙에 명시되어 있다).
- Secure: localhost를 제외하고, HTTPS를 통해야만 서버에 전송되게 한다. 항상 설정하는 게 좋다.
- HTTPOnly: 서버에서만 쿠키 접근과 설정이 가능하게 한다. 인증 토큰처럼 민감 정보를 담을 때 유용하다.
- XSS 공격이 완전히 막히는 건 아니다. 악의적인 써드파티 스크립트가 서버로 API 요청을 보낼 때에도 인증 토큰이 함께 담겨서 가기 때문.
- SameSite
- 써드파티 사이트에서도 이론상 내 서버에 API 요청을 할 수 있고, 이 때 내 도메인과 일치하는 쿠키는 함께 전송된다. 이런 쿠키를 써드파티 쿠키라고 부른다. 이는 유튜브 embed 따위에서는 유용하나, 그 외 거의 모든 경우에서는 안전하지 않다. 악의적인 사이트에서 내 서버로 API 호출할 때에도 내 정보가 함께 담길 것이고, 이런 걸 CSRF 공격이라고 부른다.
- SameSite는 이를 막기 위해 2016년에 제안된 속성이다. SameSite를 이용해 퍼스트 파티, 즉 도메인이 일치하는 URL에서 요청할 때만 쿠키를 붙여주게 할 수 있다.
- 참고로
a.github.io
와b.github.io
는 SameSite가 아니고,my-site.com
과sub.my-site.com
은 SameSite다. SameSite=Strict
: 퍼스트 파티에게만 간다.SameSite=Lax
: Strict보다 살짝 완화된 기준이다. 써드파티에서 퍼스트 파티로 유저 클릭이나 폼 전송 따위에 의한 top-level 네비게이션을 했을 때 전송된다.- 2020년 초부터 시작해서 대부분의 메이저 브라우저에서 SameSite의 기본값을
Lax
로 지정하기 시작했다. SameSite=None
: 과거와 같음.- (MDN 문서, web.dev 아티클, SameSite=Lax를 다룬 블로그 글도 참고.)
프라이버시와 써드파티 쿠키
- 여러 웹사이트에 걸쳐 추적되어 개인화된 광고를 띄우는 기작은 대략 이러하다.
- 어떤 웹사이트에 써드파티 서비스를 위한 스크립트나 iframe embed가 추가된다.
- 그 서비스에게 API 요청을 하면, 본인의 도메인에 대한 쿠키를 HTTP 응답으로 지정할 수 있다.
- 이 쿠키는, 그 써드파티를 embed하는 다른 웹사이트에서 동일하게 접근할 수 있다.
- 이 쿠키를 이용해 당신을 여러 웹사이트에 걸쳐 인지하고, 개인화 광고를 뿌린다.
- 이를 막기 위해 Firefox를 비롯한 많은 브라우저들이 ETP(Enhanced tracking protection)라는 기능을 통해 유명한 써드파티 추적 쿠키를 금지하기 시작했다.
- 그러나 추적 쿠키의 목록이 불완전하므로, 브라우저에서는 아예 써드파티 쿠키를 제거하려는 계획을 세우고 있다.
- 문제는 이렇게 하면 추적 외에 실제로 유용하게 쓰일 수 있는 써드파티 쿠키까지 막힌다는 건데, 그래서 새로운 API인 Storage Access라는 것도 제시되었다. 사용자의 명시적 허용을 통해서만 써드파티 쿠키를 허용하는 것.