HTTP 쿠키 완벽 가이드

김규리·2025년 1월 9일
1
post-thumbnail

세션 관리

HTTP는 상태 정보를 유지하지 않는다. (Stateless)
이는 서버와 클라이언트 사이에서 한 번 통신(request <-> response)이 이루어지고 나면, 그 연결이 즉시 종료된다는 것을 의미한다.

이러한 특성은 서버 자원을 효율적으로 사용하기 위함이다. 만약 모든 클라이언트와 서버가 지속적으로 연결을 유지한다면, 실제 통신이 없는 상태에서도 서버 자원이 불필요하게 소비될 것이다.

Stateless 특성으로 인해 서버는 이전 요청과 현재 요청이 동일한 클라이언트에서 온 것인지 구분할 수 없다. 이는 사용자의 로그인 상태와 같은 중요한 상태 정보를 유지하기 어렵게 만든다. 이러한 문제를 해결하기 위해 쿠키와 세션을 사용한다.


쿠키(Cookie)는 최대 4KB 크기의 문자열 데이터로, HTTP 통신에서 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각이다. 브라우저는 이 데이터를 로컬에 저장해두었다가, 동일한 서버에 재요청할 때 저장된 데이터를 함께 전송한다.

쿠키는 브라우저 측에 사용자 상태 정보를 저장하여, 서로 다른 HTTP 요청이 동일한 브라우저에서 발생했는지를 식별하는 데 사용된다. 이를 통해 서버는 Stateless한 HTTP 프로토콜 환경에서도 사용자의 로그인 상태와 같은 상태 정보를 유지할 수 있다.

HTTP 쿠키의 주요 용도는,

  • 사용자 세션 관리
  • 개인화된 사용자 설정 저장
  • 사용자 행동 추적 및 분석

이다.

  1. 클라이언트가 서버에 최초 HTTP request를 전송
  2. 서버는 HTTP response를 보낼 때 Set-Cookie 헤더에 상태 정보를 담아 쿠키를 전송
  3. 클라이언트(브라우저)는 받은 쿠키를 브라우저에 보관
  4. 이후 클라이언트가 동일한 서버에 요청할 때마다 HTTP request 헤더의 Cookie 필드에 저장된 쿠키를 포함하여 전송
  5. 서버는 전달받은 쿠키를 확인하여 클라이언트를 식별하고, 필요한 경우 쿠키를 갱신하여 response와 함께 다시 전송

과거에는 클라이언트 측의 데이터 저장소로 쿠키가 주로 사용되었다. 하지만 쿠키는 매 HTTP request마다 헤더에 포함되어 전송되기 때문에 쿠키에 저장된 데이터가 많을수록 request가 무거워진다.

따라서 최근에는 클라이언트 측 데이터 저장소로 Web Storage API(local storage, session storage)를 사용하는 것을 권장한다고 한다.


서버의 Set-Cookie 동작을 실제로 확인해보기 위해, 깃허브를 예시로 살펴보았다.

먼저 깃허브의 기존 쿠키를 삭제하고 페이지를 새로고침했다.

개발자 도구의 네트워크 탭을 통해 서버의 응답을 확인해보면, HTTP 응답 헤더에 여러 개의 Set-Cookie 필드가 포함된 것을 볼 수 있다.

이렇게 전송된 쿠키는 브라우저에 저장되며, 이를 개발자 도구에서 직접 확인할 수 있다. 개발자 도구의 애플리케이션 > Storage > Cookies 탭으로 이동하면 각 쿠키의 상세 정보를 확인할 수 있다

이러한 과정을 통해 서버가 Set-Cookie 헤더로 클라이언트에게 쿠키를 전달하고, 브라우저가 이를 저장하는 과정을 실제로 확인할 수 있다.


쿠키 필드

velog 쿠키 [벨로그에서 사용하는 쿠키]


깃허브 쿠키 [깃허브에서 사용하는 쿠키]


쿠키의 각 필드가 무엇을 뜻하는지 알아보자!

  • 이름 쿠키의 이름

  • 쿠키에 저장된 실제 데이터 값

  • Domain 쿠키가 유효한 도메인 범위를 지정한다. 해당 도메인과 그 하위 도메인에서만 쿠키에 접근 가능하다.

  • Path 쿠키가 유효한 경로를 지정한다. 지정된 경로와 그 하위 경로에서만 쿠키에 접근이 가능하다.

  • Expires/Max-Age 쿠키의 만료 시간을 지정한다. 세션 쿠키의 경우 이 값이 '세션'으로 표시되며, 브라우저 세션이 종료될 때 삭제된다. 단, 일부 브라우저는 세션을 복원하는 기능이 있어 세션 쿠키가 계속 유지될 수 있다.

  • Size 쿠키의 크기를 바이트 단위로 나타낸다. 최대 4096바이트까지 저장할 수 있다.

  • HttpOnly JavaScript를 통한 쿠키 접근을 제한한다. 설정 시 Document.cookie API로 접근이 불가능하며, XSS(Cross-site 스크립팅) 공격 방지에 도움이 된다.

  • Secure 이 필드가 체크된 경우 HTTPS 프로토콜을 사용하는 암호화된 요청에서만 쿠키가 전송된다.

  • SameSite 해당 속성을 사용하면 Cross-site 요청 시 해당 쿠키 는 전송되지 않는다. CSRF(Cross-site 요청 위조) 공격 방지에 효과적이다. 인증 쿠키가 전달되지 않으면 해당 공격은 "인증되지 않은 요청"이 되므로 공격이 실패하기 때문이다.

  • Partitioned 독립적인 파티션 상태가 있는 쿠키의 경우, 파티션 키는 쿠키를 설정하는 엔드포인트에 대한 요청(request)이 시작될 때 브라우저가 방문한 최상위 URL의 사이트이다. 쉽게 말하면 서드파티 쿠키의 파티션 키를 설정한다. 파티션 키는 서드파티 쿠키가 생성될 때 해당 서드파티가 삽입된 메인 웹사이트의 주소이다. 이를 통해 크로스 사이트 추적을 방지하고 사용자의 개인정보를 보호한다.

  • Priority 과거 브라우저의 쿠키 저장 공간 부족 시 쿠키 삭제 우선순위를 결정하는 데 사용되었으나, 현재는 지원이 중단되었다.


Domain

벨로그는 graphql을 사용한다.

도메인 속성이 쿠키 전송에 미치는 영향을 벨로그를 통해 살펴보았다.

벨로그에서 네트워크 탭을 열어보면,
'https://v2.velog.io/graphql '로 request를 보내는 것을 확인할 수 있다.

이때 요청 헤더의 쿠키를 살펴보면, 저장된 쿠키들 중 일부만 전송되는 것을 볼 수 있다. 이는 각 쿠키의 도메인 설정과 관련이 있다:

  1. v2cdn.velog.io 도메인의 쿠키 현재 요청 도메인인 v2.velog.io와 정확히 일치하지 않아 전송되지 않음
  2. velog.io 도메인의 쿠키 마찬가지로 정확히 일치하지 않아 전송되지 않음
  3. .velog.io 도메인의 쿠키 도메인 앞에 점(.)이 붙어 있어 velog.io와 그 하위 도메인(v2.velog.io)에서 모두 사용 가능하므로 전송됨

이처럼 도메인 속성 앞에 점(.)을 붙이면 해당 도메인과 모든 하위 도메인에서 쿠키를 사용할 수 있다.

HttpOnly

벨로그의 쿠키를 개발자 도구에서 확인해보면, access_tokenrefresh_token에 HttpOnly 속성이 설정되어 있는 것을 볼 수 있다.

HttpOnly가 설정된 쿠키는 JavaScript를 통한 접근이 불가능하다. 이를 확인하기 위해 브라우저 콘솔에서 document.cookie를 실행해보면, access_tokenrefresh_token은 출력되지 않는 것을 확인할 수 있다.

이러한 HttpOnly 설정은 보안을 위한 것으로, JavaScript를 통한 토큰 탈취를 방지할 수 있다. 쿠키는 HTTP 요청 시에만 서버로 전송되며, 클라이언트 측 스크립트로는 접근이 불가능하다.

쿠키 생성

그냥 js-cookie 라이브러리 쓰세효

쿠키 생성은 간단하다. 위에서도 언급했듯 쿠키는 최대 4KB의 문자열 데이터이기 때문에, 문자열을 작성하면 된다.

document.cookie = "name=gyur1kim;";

가장 기본적인 형태로, 쿠키의 이름과 값을 설정한다. 여기에 위에서 정리한 추가 필드를 옵션으로 작성하면 된다. 각 필드 사이에는;로 구분한다.

  • Domain ;Domain=velog.io

  • Path ;Path=/

  • Expires/Max-Age
    - ;Expires=date-in-UTCString-format (특정 날짜 지정)
    - ;MaxAge=max-age-in-seconds (현재 시점부터의 유효 시간)

  • Secure ;Secure

  • SameSite ;SameSite

    • ;SameSite=Lax : 기본값, 일부 크로스 사이트 GET 요청에만 쿠키 전송
    • ;SameSite=Strict : 같은 도메인의 요청에만 쿠키 전송
    • ;SameSite=None : 모든 크로스 사이트 요청에 쿠키 전송 (반드시 Secure와 함께 사용)
  • Partitioned ;Partitioned

HttpOnly 쿠키는 JavaScript로 설정할 수 없으며, 서버에서만 설정 가능하다. 쿠키 값에 특수문자가 포함된 경우 encodeURIComponent()로 인코딩 필요하며, 여러 개의 쿠키를 설정할 때는 각각 document.cookie를 통해 생성해야 한다.

사용 예시

// 만료일을 지정한 예시
document.cookie 
  = "name=gyur1kim; expires=Fri, 31 Dec 9999 23:59:59 GMT; SameSite=None; Secure";

// MaxAge를 사용한 예시
document.cookie 
  = "name2=gyur2kim; Domain=.velog.io; Path=/; MaxAge=360000; SameSite=Lax; Secure";




출처

profile
먹바눕

2개의 댓글

comment-user-thumbnail
2025년 1월 12일

잘 읽었습니다! 너무 유익해요 뉴진스보다 김규리!

1개의 답글