콘텐츠로 건너뛰기

Cookie 보안 플래그 완전 가이드|Secure / HttpOnly / SameSite / __Host-

카테고리: 웹 보안

웹 애플리케이션의 세션 관리에 가장 많이 사용되는 쿠키이지만, 올바르게 설정하지 않으면 세션 하이재킹 (session hijacking), CSRF (cross-site request forgery), XSS를 통한 토큰 탈취 같은 공격을 초래합니다. 본 글에서는 쿠키에 추가해야 할 4가지 주요 플래그 (Secure / HttpOnly / SameSite / __Host- 접두사)의 의미와 구현 시 주의할 점을 정리합니다.

Set-Cookie 헤더 구조

서버가 브라우저에 쿠키를 설정할 때 HTTP 응답에 다음과 같은 헤더를 반환합니다.

Set-Cookie: session_id=abc123; Path=/; Domain=example.com; Expires=Wed, 22 Apr 2026 10:00:00 GMT; Secure; HttpOnly; SameSite=Lax

세미콜론으로 구분된 복수의 속성이 있지만, 크게 나누면 다음 2 종류가 있습니다.

  1. 스코프 속성: Path / Domain / Expires / Max-Age — Cookie가 언제 어디로 전송되는지 결정
  2. 보안 속성: Secure / HttpOnly / SameSite — 전송/접근 제한

Secure — HTTPS로만 전송

Secure 속성이 있는 쿠키는 브라우저에서 HTTPS 연결일 때만 서버로 전송됩니다. 없으면 피해자가 http://로 사이트에 접근할 때 쿠키가 평문으로 전송되어 중간자 공격(Man-in-the-Middle)으로 세션 ID가 탈취될 수 있습니다.

철칙: 인증 관련 쿠키에는 반드시 붙이세요. 로컬 개발은 localhost이므로 HTTPS가 아니어도 Secure 쿠키가 전송되지만, 본번의 HTTPS를 전제로 하면 문제없습니다.

HttpOnly — JavaScript에서 접근 불가

HttpOnly를 붙이면 document.cookie로 읽을 수 없게 됩니다. 이로 인해 XSS 공격으로 삽입된 JavaScript가 Cookie를 도용할 수 없게 됩니다.

XSS는 여전히 발생 가능한 취약점이므로 세션 쿠키에는 필수로 생각하세요. JavaScript 측에서 쿠키 값을 읽을 필요가 있는 경우(예: CSRF 토큰), 읽기 전용의 별도 쿠키를 만드는 것이거나 <meta> 태그를 통해 값을 전달하는 것이 원칙입니다.

SameSite — 크로스사이트 요청에서의 전송 제어

SameSite 속성은 CSRF 대책의 핵심입니다. 값은 다음의 3가지입니다:

동작CSRF 방어
Strict크로스사이트 요청에는 전혀 보내지 않음 (외부 링크에서 올 때도)최강
Lax (기본값)최상위 GET 네비게이션에서만 전송 (링크 클릭 OK, POST 폼 NG)강함
None모든 크로스사이트 요청으로 전송 (Secure 필수)없음

2020년 이후의 모던 브라우저는 지정되지 않은 SameSite를 Lax로 취급하므로 명시하지 않아도 최소한의 CSRF 보호를 얻을 수 있습니다. 하지만 의도를 명확히 하기 위해 명시적으로 설정하는 것이 좋습니다.

SSO 연동이나 iframe 임베드에서 SameSite=None을 사용할 경우, 반드시 Secure도 함께 설정해야 하는 것이 현대 브라우저의 요구사항입니다. Secure가 없는 SameSite=None 쿠키는 브라우저에 의해 거부됩니다.

__Host- / __Secure- 접두사

Cookie 이름이 __Host-로 시작하는 경우 브라우저는 다음 3 가지 조건을 강제합니다.

  • Secure 플래그 필수
  • Domain 속성을 붙여서는 안 됩니다 (=요청을 보낸 정확한 호스트만)
  • Path=/이어야 함

이들은 「다른 서브도메인에서 덮어쓸 수 없음」「Host 헤더 위조로 임의로 쿠키를 설정할 수 없음」이라는 강력한 보장을 제공합니다. 세션 쿠키에는 __Host-session과 같이 프리픽스를 붙이는 것이 가장 견고합니다.

다른 __Secure- 접두사는 필수 Secure 플래그만 적용합니다 (Domain / Path 제약 없음).

4096 바이트 제한

Cookie의 value는 RFC 6265에서 총 4096 바이트로 권장됩니다. 큰 JSON이나 배열을 Cookie에 담으면 이를 초과할 수 있으며, 브라우저가 조용히 잘라낼 수 있습니다. 큰 데이터는 서버 사이드 세션에 두고, Cookie에는 세션 ID만 넣는 것이 정석입니다.

구현 예시: 인증 세션 쿠키

올바르게 설정된 인증 쿠키는 다음과 같은 형태입니다.

Set-Cookie: __Host-session=eyJ0eXAi...; Path=/; Max-Age=3600; Secure; HttpOnly; SameSite=Lax
  • __Host-: 서브도메인 오염 및 호스트 위장 방지
  • Path=/: 사이트 전체에서 접근 가능
  • Max-Age=3600: 1시간 후 만료
  • Secure: HTTPS를 통해서만 전송
  • HttpOnly: JavaScript에서 접근 불가
  • SameSite=Lax: 크로스사이트 POST에서 전송되지 않음 (CSRF 보호)

PHP (Laravel) 예제

// config/session.php
return [
    'secure'     => true,      // Secure フラグ
    'http_only'  => true,      // HttpOnly フラグ
    'same_site'  => 'lax',    // SameSite=Lax
    'path'       => '/',
    'cookie'     => '__Host-session',
];

Node.js (Express) 예제

const session = require('express-session');

app.use(session({
  name: '__Host-session',
  secret: process.env.SESSION_SECRET,
  cookie: {
    secure:   true,
    httpOnly: true,
    sameSite: 'lax',
    path:     '/',
    maxAge:   3600 * 1000,
  },
}));

기존 사이트의 Cookie 설정을 확인하는 방법

DevLab의 쿠키 검사 도구를 사용하면 자신의 사이트나 타사 사이트의 쿠키가 올바르게 설정되었는지 즉시 확인할 수 있습니다. URL을 입력하기만 하면 반환된 모든 Set-Cookie 헤더를 분석하고 다음과 같은 진단을 표시합니다.

  • 각 Cookie의 Secure / HttpOnly / SameSite 유무
  • SameSite=None인데 Secure가 없는 등의 위반
  • __Host- 접두사의 일관성
  • 4096 바이트 초과 경고
  • 전체 요약 (Secure 비율 / HttpOnly 비율 / SameSite 분포)

요약

Cookie 보안 플래그는 임의로 설정하는 것이 아니라, 공격 시나리오와 대응 방안을 이해한 후에 설정하는 것이 중요합니다. 최소한 프로덕션 환경의 인증 세션 Cookie에는 Secure + HttpOnly + SameSite + __Host- 접두사 + 짧은 Max-Age를 붙여야 합니다. 기존 사이트의 설정 재검토에는 Cookie 검사 도구의 사용을 권장합니다.

❓ 자주 묻는 질문

SameSite=Lax 와 Strict 는 어떻게 구분해 쓰나요?
로그인 유지용 세션 쿠키는 Lax 가 기본 답입니다. Strict 로 하면 외부 사이트 링크로 돌아온 첫 요청에 쿠키가 실리지 않아 로그인 상태인데도 비로그인으로 보입니다. 결제 확정이나 비밀번호 변경처럼 타 사이트에서 실행되면 곤란한 동작 전용 쿠키만 Strict 로 두세요.
HttpOnly 를 붙이면 XSS 를 막을 수 있나요?
막지 못합니다. HttpOnly 가 막는 것은 XSS 가 성립한 뒤 document.cookie 로 토큰을 빼내는 일뿐입니다. 스크립트 주입 자체는 멈추지 않으므로 공격자는 훔치는 대신 그 자리에서 요청을 보낼 수 있습니다. XSS 대책의 본체는 출력 이스케이프와 CSP 이고 HttpOnly 는 피해를 한 단계 좁히는 보험입니다.
__Host- 프리픽스는 무엇을 보장하나요?
브라우저가 Secure, Path=/, Domain 속성 없음을 강제하고 조건을 만족하지 않는 Set-Cookie 는 통째로 거부합니다. 효과는 서브도메인의 덮어쓰기를 막는 것입니다. Domain 을 쓸 수 없으므로 user.example.com 이 example.com 의 쿠키를 바꿔치기할 수 없고, 서브도메인 탈취를 통한 세션 고정을 구조적으로 차단합니다.