Set-Cookie
사용법
Set-Cookie 헤더는 이름-값 쌍과, 쿠키의 범위·수명·보안 속성을 제어하는 선택적 속성들을 저장하라고 클라이언트에 지시합니다. 각 Set-Cookie 헤더는 정확히 하나의 쿠키를 설정합니다. 여러 쿠키를 보내는 서버는 같은 응답에 여러 Set-Cookie 헤더를 넣습니다.
일반적인 구문은 등호로 구분된 쿠키 이름과 값에 이어, 세미콜론으로 구분된 선택적 속성들이 오는 형태입니다.
Set-Cookie: <name>=<value>; <attributes>
쿠키 이름은 제어 문자, 공백, 탭, 그리고 구분 문자 ( ) < > @ , ; : \ ” / [ ] ? = { } 를 제외한 US-ASCII 문자를 받습니다. 쿠키 값은 제어 문자, 공백 문자, 큰따옴표, 쉼표, 세미콜론, 역슬래시를 제외한 US-ASCII 문자를 받습니다. 값은 선택적으로 큰따옴표로 감쌀 수 있습니다.
브라우저는 프런트엔드 JavaScript가 Fetch API와 XMLHttpRequest를 통해 Set-Cookie 헤더를 읽는 것을 막습니다. 이 헤더는 Fetch 명세에서 금지된 응답 헤더 이름입니다. CORS 응답의 쿠키는 요청에 자격 증명이 포함되지 않는 한 무시됩니다.
쿠키 접두사
쿠키 이름 접두사는 브라우저가 강제하는 추가 제약을 부과하여, 쿠키가 어디서 어떻게 설정되었는지에 대한 보장을 제공합니다.
__Secure- 접두사는 Secure 속성과 HTTPS 오리진을 요구합니다. 이는 HTTP 전용 사이트가 보안 쿠키와 같은 이름을 공유하는 쿠키를 설정하지 못하게 막습니다.
Set-Cookie: __Secure-ID=abc; Secure; Path=/
__Host- 접두사는 더 엄격한 요건을 더합니다. Secure 속성, Domain 속성 없음, 그리고 Path를 /로 설정하는 것입니다. 이는 쿠키를 정확한 오리진 호스트명에 묶어 하위 도메인의 간섭을 막습니다.
Set-Cookie: __Host-ID=abc; Secure; Path=/
__Http- 접두사는 Secure와 HttpOnly 속성을 모두 요구하며, JavaScript가 아니라 Set-Cookie 헤더를 통해서만 설정할 수 있습니다.
Set-Cookie: __Http-ID=abc; Secure; HttpOnly
__Host-Http- 접두사는 __Host-와 __Http-의 제약을 모두 결합하여, 사용 가능한 가장 제한적인 쿠키 바인딩을 만듭니다.
Set-Cookie: __Host-Http-ID=abc; Secure; HttpOnly; Path=/
참고
__Http-와 __Host-Http- 접두사는 브라우저가 널리 강제하는 기존의 __Secure-, __Host- 접두사와는 별개인 또 다른 쿠키 접두사 제안에서 나온 것입니다. 이 새로운 접두사들은 아직 제안 단계에 머물러 있습니다.
SEO 영향
Googlebot은 오리진이 설정한 쿠키를 전송하지만 별개의 크롤 세션 간에 쿠키를 유지하지는 않습니다. 애셋 도메인의 큰 쿠키는 렌더링 중 요청 크기를 키웁니다. 정적 애셋용으로 쿠키 없는 도메인을 쓰면 이 부담을 피할 수 있습니다. 크롤러가 페이지를 보지 못하게 막는 쿠키 의존 로직 뒤에 콘텐츠를 가두지 마십시오.
Expires
Expires 속성은 HTTP-date 형식으로 절대 만료 날짜를 설정합니다. 이 날짜 이후 클라이언트는 더 이상 쿠키를 보내지 않습니다. Max-Age와 함께 생략되면 쿠키는 클라이언트가 닫힐 때 제거되는 세션 쿠키가 됩니다. 브라우저는 응답의 Date 헤더를 사용해 시계 오차를 보정합니다.
Expires=Thu, 31 Dec 2026 23:59:59 GMT
참고
브라우저는 Expires 값을 쿠키가 설정된 시점으로부터 400일로 제한합니다. 이 제한은 대략 1년에 한 번 방문하는 사이트가 쿠키를 유지할 수 있게 하면서도 무기한 지속되는 것은 막습니다.
Max-Age
Max-Age 속성은 클라이언트가 응답을 받은 시점으로부터의 쿠키 수명을 초 단위로 설정합니다. 값이 0이거나 음수이면 쿠키가 즉시 만료됩니다. Expires와 Max-Age가 모두 있으면 Max-Age가 우선합니다.
Max-Age=2592000
JavaScript의 Cookie Store API도 cookieStore.set() 메서드를 통해 maxAge 옵션을 노출하여 프로그래밍 방식의 쿠키 관리에서 이 속성을 반영합니다. 이 API는 같은 쿠키에 expires와 maxAge를 동시에 설정하는 것을 허용하지 않습니다.
참고
브라우저는 Max-Age 값을 Expires 제한과 동일하게 400일(34,560,000초)로 제한합니다.
Domain
Domain 속성은 어떤 호스트가 쿠키를 받을지 지정합니다. 설정하면 쿠키는 지정된 도메인과 그 모든 하위 도메인에서 사용할 수 있습니다. 생략하면 쿠키는 기본적으로 발급한 호스트에만 한정되며 하위 도메인은 제외됩니다(호스트 전용 쿠키). 현재 도메인이나 현재 호스트의 상위 도메인만 유효합니다. 앞에 붙은 점은 무시됩니다.
Domain=example.re
Path
Path 속성은 쿠키 전송을 지정된 URL 경로 접두사와 일치하는 요청으로 제한합니다. 슬래시 /가 경로 세그먼트를 구분합니다. Path=/docs 인 쿠키는 /docs, /docs/, /docs/Web/HTTP 에는 일치하지만 / 나 /docsets 에는 일치하지 않습니다.
Path=/
참고
Path 속성은 보안 메커니즘이 아닙니다. 같은 오리진의 어떤 스크립트든 경로 제한과 무관하게 모든 쿠키에 접근할 수 있습니다.
Secure
Secure 속성은 쿠키를 HTTPS 연결로 제한합니다. 브라우저는 보안 쿠키를 암호화되지 않은 HTTP로 결코 보내지 않습니다. 안전하지 않은 오리진은 이 속성을 가진 쿠키를 설정할 수 없습니다. 개발 중 localhost는 HTTPS 요건에서 면제됩니다.
HttpOnly
HttpOnly 속성은 document.cookie, Cookie Store API를 비롯한 DOM 인터페이스를 통한 JavaScript의 쿠키 접근을 차단합니다. 쿠키는 fetch()와 XMLHttpRequest로 JavaScript가 시작한 HTTP 요청에는 여전히 전송됩니다. 이 속성은 쿠키 값을 훔치려는 교차 사이트 스크립팅(XSS) 공격을 완화합니다.
SameSite
SameSite 속성은 브라우저가 교차 사이트 요청에 쿠키를 보낼지 제어합니다. 세 가지 값이 정의되어 있습니다.
Strict는 동일 사이트 요청에만 쿠키를 보냅니다. 외부 사이트의 링크 클릭을 포함한 교차 사이트 내비게이션에는 쿠키가 포함되지 않습니다.
Lax는 동일 사이트 요청과, URL 표시줄이 바뀌는 교차 사이트 최상위 내비게이션에 쿠키를 보냅니다. 하위 리소스 요청, fetch() 호출, iframe 내비게이션에는 쿠키가 포함되지 않습니다. 대부분의 브라우저는 SameSite 속성이 지정되지 않으면 기본적으로 Lax를 적용합니다.
None은 교차 사이트 요청을 포함한 모든 요청에 쿠키를 보냅니다. SameSite=None을 사용할 때는 Secure 속성이 필요합니다. 스킴이 다른(HTTP 대 HTTPS) 쿠키는 교차 사이트로 취급됩니다.
SameSite=Lax
Partitioned
Partitioned 속성은 쿠키 오리진과 최상위 사이트 양쪽을 키로 삼는 분할된 스토리지에 쿠키를 저장합니다. shop.example.org에 임베드된 cdn.example.re가 설정한 분할 쿠키는 cdn.example.re가 shop.example.org에 임베드되었을 때만 전송되고, 다른 사이트에 임베드되었을 때는 전송되지 않습니다.
이 속성은 CHIPS(Cookies Having Independent Partitioned State) 제안의 일부입니다. 이 속성은 임베드 위젯, CDN 로드 밸런싱, 헤드리스 CMS 공급자 같은 정당한 교차 사이트 쿠키 사용 사례를 가능하게 하면서도 전면적인 교차 사이트 추적 능력은 부여하지 않습니다.
Secure 속성이 필요합니다. 쿠키를 정확한 오리진에 묶기 위해 __Host- 접두사를 사용하기를 권장합니다.
Set-Cookie: __Host-sess=abc; SameSite=None; Secure; Path=/; Partitioned
Chromium 기반 브라우저와 Firefox가 지원합니다. Safari는 별도의 메커니즘으로 서드파티 쿠키를 기본 분할하며 이 속성을 사용하지 않습니다.
예시
만료 속성이 없는 세션 쿠키입니다. 클라이언트 세션이 끝나면 쿠키가 제거됩니다.
Set-Cookie: sessionId=38afes7a8
수명이 30일인 지속 쿠키입니다. Max-Age 속성은 현재 시각을 기준으로 만료를 설정합니다.
Set-Cookie: id=a3fWa; Max-Age=2592000
인증 토큰에 적합한 보안 속성을 갖춘 쿠키입니다. HttpOnly 속성은 JavaScript 접근을 막고, Secure는 HTTPS로 제한하며, SameSite=Strict는 교차 사이트 전송을 방지합니다.
Set-Cookie: __Host-token=eyJhbGci; Secure; HttpOnly; SameSite=Strict; Path=/
교차 사이트 임베드를 위한 분할된 서드파티 쿠키입니다. Partitioned 속성은 임베드가 나타나는 특정 최상위 사이트로 쿠키를 격리합니다.
Set-Cookie: __Host-embed=34d8g; SameSite=None; Secure; Path=/; Partitioned
하나의 응답에서 여러 쿠키를 설정합니다. 각 쿠키에는 자체 Set-Cookie 헤더가 필요합니다.
Set-Cookie: theme=dark; Path=/; Max-Age=31536000
Set-Cookie: __Host-sid=x8Kp2; Secure; HttpOnly; SameSite=Lax; Path=/
문제 해결
쿠키가 저장되지 않거나 엉뚱한 요청에 실려 가는 문제는 속성이 어긋났거나 브라우저의 강제 정책 때문인 경우가 많습니다.
HTTP에서 Secure 플래그 때문에 쿠키가 저장되지 않습니다. Secure 속성에는 HTTPS 연결이 필요합니다. 평문 HTTP에서 Secure와 함께 설정된 쿠키는 조용히 폐기됩니다. 브라우저 주소 표시줄에서 프로토콜을 확인하고 DevTools의 Network 탭에서 Set-Cookie 헤더를 살펴보십시오. 개발 중 localhost는 이 제한에서 면제됩니다.
교차 사이트 요청에 쿠키가 전송되지 않습니다(SameSite 기본값). 최신 브라우저는 SameSite 속성이 없으면 기본적으로 SameSite=Lax를 적용합니다. fetch() 호출, iframe, 이미지 로드 같은 교차 사이트 하위 요청에는 쿠키가 포함되지 않습니다. 쿠키가 반드시 교차 사이트로 전달되어야 한다면 SameSite=None; Secure 를 추가하거나, 교차 사이트 의존성을 피하도록 흐름을 재구성하십시오.
쿠키 경로 불일치. Path=/app 으로 설정된 쿠키는 /api 나 / 를 대상으로 하는 요청에 전송되지 않습니다. Path 값이 쿠키를 필요로 하는 요청 경로와 일치하는지 확인하십시오. Path=/ 로 설정하면 쿠키를 사이트 전역에서 사용할 수 있습니다.
Domain 속성 범위 문제. Domain=sub.example.re 로 설정된 쿠키는 example.re 에 전송되지 않습니다. Domain 속성을 생략하면 정확한 호스트명으로 제한된 호스트 전용 쿠키가 만들어집니다. 값 앞에 붙은 점은 브라우저가 무시합니다. DevTools의 Application > Cookies 패널에서 저장된 각 쿠키의 실제 도메인을 확인하십시오.
브라우저 개인정보 보호 기능이 서드파티 쿠키를 차단합니다. Safari는 지능형 추적 방지를 통해 서드파티 쿠키를 기본 차단합니다. Firefox의 향상된 추적 방지와 Chrome의 Privacy Sandbox도 비슷한 제한을 적용합니다. Partitioned 속성(CHIPS)은 정당한 교차 사이트 쿠키 사용 사례를 위한 표준 기반 경로를 제공합니다. 여러 브라우저에서 테스트하여 동작을 확인하십시오.
쿠키가 최대 크기를 초과합니다. 브라우저는 쿠키 하나당 약 4096바이트(이름, 값, 속성을 합친 크기)의 제한을 적용합니다. 크기를 초과한 쿠키는 조용히 버려집니다. 큰 페이로드는 서버 측 세션으로 옮기고 쿠키에는 세션 식별자만 저장하십시오.
저장된 쿠키 디버깅하기. DevTools > Application > Cookies를 열면 현재 사이트의 모든 쿠키를 속성, 만료, 크기와 함께 살펴볼 수 있습니다. document.cookie API는 HttpOnly 쿠키를 노출하지 않습니다. 서버가 반환한 원시 Set-Cookie 헤더를 보려면 curl -v 를 사용하십시오.