본문 바로가기
source-code/FrontEnd

브라우저에 데이터 저장하기 - 쿠키와 document.cookie

by mattew4483 2023. 8. 17.
728x90
반응형

쿠키와 document.cookie

쿠키

  • 브라우저에 저장되는 작은 크기의 문자열 →RFC 6265 명세에서 정의한 HTTP 프로토콜의 일부.
  • 주로 웹 서버에 의해 만들어짐.
    - 서버가 HTTP 응답 헤더의 Set-Cookie에 내용을 넣어 전달.
    - 브라우저는 이 내용을 자체적으로 브라우저에 저장 = 이것이 쿠키!
  • 브라우저는 사용자가 쿠키를 생성한 동일 서버(사이트)에 접속할 때마다, 쿠키의 내용을 Cookie 요청 헤더에 넣어서 함께 전달.
  • 클라이언트 식별과 같은 인증에서 주로 사용됨.
    1. 사용자가 로그인하면, 서버는 HTTP 응답 헤더의 Set-Cookie에 담긴 “세션 식별자(session identifier)” 정보를 사용해 쿠키를 설정.
    2. 사용자가 동일 도메인에 접속하려고 하면, 브라우저는 HTTP Cookie 헤더에 인증 정보가 담긴 고윳값(세션 식별자)을 함께 실어 서버에 요청 보냄.
    3. 서버는 브라우저가 보낸 요청 헤더의 세션 식별자를 읽어 사용자를 식별.
  • document.cookie 프로퍼티를 이용해 브라우저에서도 쿠키에 접근 가능.

쿠키 읽기

alert( document.cookie ); // cookie1=value1; cookie2=value2;...
  • document.cookie → name=value 쌍으로 구성됨. 이때 각 쌍은 ; 로 구분하며, 쌍 하나는 하나의 독립된 쿠기를 나타냄.
    • ; 을 기준으로 document.cookie의 값을 분리하면, 원하는 쿠키를 찾을 수 있음.

쿠키 쓰기

  • document.cookie에 직접 값을 쓸 수 O.
    • 이때 cookie는 데이터 프로퍼티가 아닌, 접근자(accessor) 프로퍼티!
  • document.cookie에 값을 할당하면, 브라우저는 이 값을 받아 해당 쿠키를 갱신. 이때, 다른 쿠키의 값은 변경되지 않음.
document.cookie = "user=John"; // 이름이 'user'인 쿠키의 값만 갱신함
alert(document.cookie); // 모든 쿠키 보여주기
// -> 명시된 쿠키인 user의 값만 변경된 모습!

 

  • 쿠키의 name과 value에 특별한 제약은 존재X.
    • 하지만 형식의 유효성을 일관성 있게 유지하기 위해, 
      반드시 내장 함수 encodeURIComponent를 사용해 이름과 값을 이스케이프 처리해 줘야 함!
// 특수 값(공백)은 인코딩 처리해 줘야 합니다.
let name = "my name";
let value = "John Smith"

// 인코딩 처리를 해, 쿠키를 my%20name=John%20Smith 로 변경하였습니다.
document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);

alert(document.cookie); // ...; my%20name=John%20Smith

 

  • 제약 사항
    • encodeURIComponent로 인코딩한 이후의 name=value 쌍은 4KB를 넘을 수 없음. 
      (이 용량을 넘는 정보는 쿠키에 저장할 수 없다)
    • 도메인 하나당 저장할 수 있는 쿠키의 개수는 20여 개 정도로 한정! 
      (개수는 브라우저에 따라 조금씩 다름)

옵션

  • 쿠키에는 몇 가지 옵션이 존재 → 몇몇 옵션은 아주 중요! (꼭 지정해줘야 함)
  • 옵션은 key=value 뒤에 나열하고 ; 로 구분.
document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT"

 

1. Path
path=/mypath

  • URL path의 접두사.
  • 해당 경로 또는 해당 경로의 하위 경로에 있는 페이지만 쿠키에 접근 가능.
  • 절대 경로여야 함 - 미 지정 시 기본값은 현재 경로!
  • 특별한 경우가 아니라면, path 옵션을 path=/ 과 같이 루트로 설정해, 모든 페이지에서 쿠키에 접근할 수 있도록 해줌.

2. domain
domain=site.com

  • 쿠키에 접근 가능한 도메인을 지정.
  • 제약 존재 - 아무 도메인이나 지정할 수 있는 것은 X
  • domain 옵션에 아무 값도 넣지 않았을 경우 
    - 쿠키를 설정한 도메인에서만 쿠키에 접근 가능
    - 서브 도메인에서도 쿠키에 접근 불가능!!!
  • 서브 도메인이나 다른 도메인에서 쿠키에 접속할 방법은... 존재하지 않음.
    but domain 옵션을 명시적으로 설정함으로써 가능해짐.
// site.com에서 쿠키를 설정함
document.cookie = "user=John"

// site.com의 서브도메인인 forum.site.com에서 user 쿠키에 접근하려 함
alert(document.cookie); // 찾을 수 없음
// site.com에서
// 서브 도메인(*.site.com) 어디서든 쿠키에 접속하게 설정할 수 있습니다.
document.cookie = "user=John; domain=site.com"

// 이렇게 설정하면

// forum.site.com와 같은 서브도메인에서도 쿠키 정보를 얻을 수 있습니다.
alert(document.cookie); // user=John 쿠키를 확인할 수 있습니다.

 

3. expires와 max-age

  • expires(유효 일자)나 max-age(만료 기간) 옵션이 지정되어있지 않으면, 브라우저가 닫힐 때 쿠키도 함께 삭제됨.
    = 세션 쿠키(session cookie)
  • expires 나 max-age 옵션을 설정하면 → 브라우저를 닫아도 쿠키가 삭제되지 않음!
  • expires
    • 브라우저는 설정된 유효 일자까지 쿠키를 유지하다가, 해당 일자에 도달하면 쿠키를 자동으로 삭제.
    • 반드시 GMT(Greenwich Mean Time) 포맷으로 설정 (date.toUTCString 사용해 변환 가능)
    • 과거로 지정 시 쿠키는 바로 삭제됨.
// 지금으로부터 하루 후
let date = new Date(Date.now() + 86400e3);
date = date.toUTCString();
document.cookie = "user=John; expires=" + date;

 

  • max-age
    • expires 옵션의 대안 → 쿠키 만료 기간을 설정할 수 있도록 해줌.
    • 현재부터 설정하고자 하는 만료일시까지의 시간을 초로 환산한 값을 설정.
    • 0이나 음수값 설정 시 쿠키는 바로 삭제됨.
// 1시간 뒤에 쿠키가 삭제됩니다.
document.cookie = "user=John; max-age=3600";

// 만료 기간을 0으로 지정하여 쿠키를 바로 삭제함
document.cookie = "user=John; max-age=0";

 

4. secure
secure

  • HTTPS로 통신하는 경우에만 쿠키가 전송됨.
  • secure 옵션이 없을 경우 → http://site.com에서 설정(생성)한 쿠키를 https://site.com에서 읽을 수 있음 (반대도 가능)
  • 암호화되지 않은 HTTP 연결을 통해 전달되는 걸 원치 않을 경우 해당 옵션 사용.
// (https:// 로 통신하고 있다고 가정 중)
// 설정한 쿠키는 HTTPS 통신시에만 접근할 수 있음
document.cookie = "user=John; secure";

 

5. samesite

  • 크로스 사이트 요청 위조(cross-site request forgery, XSRF) 공격을 막기 위해 만들어진 옵션.
  • “XSRF 보호 토큰” 없이도 (이론상으로) 크로스 사이트 요청 위조를 막을 수 있음.

6. httpOnly

  • 웹서버에서 Set-Cookie 헤더를 이용해 쿠키를 설정할 때 지정 가능.
  • 클라이언트 측 스크립트(JS와 같은)가 쿠키를 사용할 수 없게 함.
    • document.cookie를 통해 쿠키를 볼 수도 없고 조작할 수도 없음!
  • 해커가 악의적인 JS 코드를 페이지에 삽입하고, 사용자가 그 페이지에 접속하기를 기다리는 방식의 공격을 예방할 때 사용.

 

유용한 쿠키 함수

  • getCookie(name)
    • 주어진 name의 쿠키를 반환
// 주어진 이름의 쿠키를 반환하는데,
// 조건에 맞는 쿠키가 없다면 undefined를 반환합니다.
function getCookie(name) {
  let matches = document.cookie.match(new RegExp(
    "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
  ));
  return matches ? decodeURIComponent(matches[1]) : undefined;
  // 쿠키값은 인코딩되어있는 상태이기 때문에 getCookie는 
  // 내장 함수인 decodeURIComponent를 이용해 쿠키값을 디코딩.
}

 

  • setCookie(name, value, options)
    • 현재 경로(path=/)를 기본으로, 주어진 name과 value를 가진 쿠키를 설정
function setCookie(name, value, options = {}) {

  options = {
    path: '/',
    // 필요한 경우, 옵션 기본값을 설정할 수도 있습니다.
    ...options
  };

  if (options.expires instanceof Date) {
    options.expires = options.expires.toUTCString();
  }

  let updatedCookie = encodeURIComponent(name) + "=" + encodeURIComponent(value);

  for (let optionKey in options) {
    updatedCookie += "; " + optionKey;
    let optionValue = options[optionKey];
    if (optionValue !== true) {
      updatedCookie += "=" + optionValue;
    }
  }

  document.cookie = updatedCookie;
}

// Example of use:
setCookie('user', 'John', {secure: true, 'max-age': 3600});

 

  • deleteCookie(name)
    • 만료 기간을 음수로 설정해, 쿠키를 삭제.
function deleteCookie(name) {
  setCookie(name, "", {
    'max-age': -1
  })
}

 

서드 파티 쿠키

  • 사용자가 방문 중인 도메인이 아닌, 다른 도메인에서 설정한 쿠키.
  • 브라우저에는 이러한 쿠키를 비활성화할 수 있는 기능 존재 → 사용 시 추적을 막을 수 있음.
  • Safari는 서드파티 쿠키를 전면적으로 허용하지 않음.
  • Firefox는 서드 파티 도메인 블랙리스트를 만들어, 리스트에 오른 도메인의 서드 파티 쿠키를 차단.

 

GDPR

  • 사용자 개인 정보 보호를 강제하는 EU 법령.
  • 쿠키를 추적하는 경우 사용자로부터 명시적인 허가를 얻어야 한다는 것이 이 법령의 중요 요건 중 하나!
  • 사용자 추적  식별에 관한 내용을 담고 있음 (단순히 정보 저장 용도로 사용 시 강제 사항을 지킬 필요는 X)
    • 인증된 사용자에 대해서만 추적 쿠키를 설정하려는 경우
      가입 양식에 “개인 정보 취급 방침 동의” 같은 확인란을 만들고, 사용자가 이에 동의할 경우에만 추적 쿠키를 설정합니다.
    • 모든 사용자를 대상으로 추적 쿠키를 설정하려는 경우
      최초 방문자에게 쿠키설정에 대한 동의를 요구하는 "작은 창"을 보여주고, 사용자가 이에 동의한 경우에만 콘텐츠를 표시하고, 추적 쿠키를 설정합니다. 새로운 방문자는 이런 절차가 번거롭다고 생각할 수 있습니다. 콘텐츠를 가리면서 "무조건 클릭해야 하는 창"을 그 누구도 달가워하지 않죠. 하지만 GDPR을 준수하려면 이 창이 반드시 있어야 합니다.
728x90
반응형

'source-code > FrontEnd' 카테고리의 다른 글

webpack - settings  (0) 2023.08.17
TDD기반 TODO 애플리케이션  (0) 2023.08.17
Atomic Design  (0) 2023.08.17
webpack - loader, optimization  (0) 2023.08.17
next input auto focus를 통한 UX 개선  (0) 2023.08.17