쿠키의 모든 것: 세션·서드파티·Secure·HttpOnly
쿠키 종류(세션/영구/서드파티)와 보안 속성(Secure·HttpOnly·SameSite)이 각각 무엇을 막는지 정리.
HTTP는 원래 “기억력이 없는” 프로토콜입니다. 요청 하나하나가 서로 독립적이라, 서버는 방금 로그인한 사용자와 처음 온 방문자를 구분할 수 없습니다. 이 간극을 메우는 것이 쿠키입니다. 서버가 응답에 Set-Cookie 헤더를 실어 보내면 브라우저가 그 값을 저장해 두었다가, 조건이 맞는 다음 요청마다 Cookie헤더로 자동으로 되돌려 보냅니다. 로그인 세션 유지, 장바구니, 언어 설정, 방문 분석까지 웹의 “상태”는 대부분 이 작은 문자열 위에서 돌아갑니다.
문제는 쿠키가 세션 그 자체라는 점입니다. 세션 쿠키를 훔치면 비밀번호를 몰라도 그 사람으로 로그인한 것과 같습니다. 그래서 쿠키에는 Secure·HttpOnly·SameSite 같은 보안 속성이 붙습니다. 이 가이드는 쿠키의 동작 원리부터 종류(세션/영구, 퍼스트파티/서드파티), 속성별로 막아 주는 공격, 그리고 그대로 복사해 쓸 수 있는 권장 설정까지 순서대로 정리합니다.
쿠키는 어떻게 오가는가 — Set-Cookie와 Cookie 헤더
흐름은 딱 두 단계입니다.
- 서버 → 브라우저: 응답에
Set-Cookie: session=abc123; Path=/처럼 헤더를 추가합니다. 이름=값 쌍 하나에 세미콜론으로 구분된 속성들이 따라붙습니다. 쿠키 하나당Set-Cookie헤더 한 줄입니다. - 브라우저 → 서버: 이후 도메인·경로·보안 조건이 맞는 모든 요청에 브라우저가
Cookie: session=abc123을 자동으로 붙여 보냅니다. 이때는 값만 가고 속성은 다시 전송되지 않습니다 — 속성은 브라우저가 “언제 보낼지”를 판단하는 규칙일 뿐입니다.
“자동으로 붙여 보낸다”는 점이 편리함의 원천이자 보안 문제의 원천입니다. 사용자가 의도하지 않은 요청(다른 사이트에서 몰래 보낸 요청)에도 쿠키가 따라가기 때문에 CSRF 같은 공격이 성립합니다. 지금 내 사이트가 실제로 어떤 쿠키를 어떤 속성으로 내려 주는지는 쿠키 검사기에 URL만 넣으면 바로 확인할 수 있습니다.
세션 vs 영구, 퍼스트파티 vs 서드파티
수명 기준으로는 두 종류입니다. Expires(만료 시각)나 Max-Age(수명 초)가 없으면세션 쿠키가 되어 브라우저를 닫으면 사라집니다. 둘 중 하나라도 있으면영구 쿠키가 되어 그 시점까지 디스크에 남습니다. 둘 다 있으면 Max-Age가 우선합니다. 로그인 세션은 짧게(수 시간~수 일), “로그인 상태 유지” 토큰은 별도 쿠키로 길게 두는 식으로 용도별로 수명을 분리하는 것이 정석입니다.
소속 기준으로는 퍼스트파티(지금 주소창에 보이는 사이트가 설정한 쿠키)와 서드파티(페이지에 삽입된 다른 도메인 — 광고·분석 스크립트 등 — 가 설정한 쿠키)로 나뉩니다. 서드파티 쿠키는 여러 사이트에 걸친 방문 추적에 쓰여 왔기 때문에 브라우저들이 단계적으로 막고 있습니다. Safari와 Firefox는 이미 기본 차단이고, Chrome도 완전 폐지 대신 사용자 선택제로 방향을 틀었지만 흐름 자체는 “서드파티 쿠키에 의존하지 말라”로 굳어졌습니다. 내 서비스의 로그인·설정 쿠키는 전부 퍼스트파티이므로 이 차단의 영향을 받지 않습니다.
보안 속성 한눈에 보기
| 속성 | 의미 | 막아 주는 것 |
|---|---|---|
Secure | HTTPS 연결에서만 전송 | 평문 HTTP 구간에서의 도청·탈취 |
HttpOnly | JavaScript(document.cookie)로 읽기 불가 | XSS 스크립트가 쿠키를 훔쳐 외부로 빼돌리는 것 |
SameSite | Strict/Lax/None — 다른 사이트발 요청에 쿠키를 붙일지 | CSRF(사용자 모르게 요청을 위조하는 공격) |
Domain | 지정하면 서브도메인 전체로 확장, 생략하면 설정한 호스트에만 | 범위를 좁혀 다른 서브도메인 유출 최소화(생략이 더 안전) |
Path | 이 경로 이하 요청에만 전송 | 불필요한 경로로의 전송 축소(보안 경계로는 약함) |
__Host- 접두사 | 이름이 __Host-로 시작하면 Secure + Path=/ 필수, Domain 금지 | 서브도메인이 같은 이름의 쿠키를 덮어쓰는 세션 고정류 공격 |
SameSite의 기본 감각은 이렇습니다. Strict는 다른 사이트에서 온 어떤 요청에도 쿠키를 붙이지 않아 가장 안전하지만, 외부 링크로 진입한 첫 화면에서 로그아웃 상태로 보이는 부작용이 있습니다. Lax는 주소창 이동·일반 링크 클릭 같은 “최상위 GET 이동”에만 붙여 주는 균형점이라 대부분의 세션 쿠키에 적합합니다. None은 어디서든 붙이는 대신 반드시Secure와 함께 써야 하며, 크로스사이트 위젯·결제창처럼 꼭 필요할 때만 씁니다.
공격별 방어 짝과 권장 레시피
| 공격 | 수법 | 1차 방어 속성 |
|---|---|---|
| XSS 쿠키 탈취 | 주입된 스크립트가 document.cookie를 읽어 공격자 서버로 전송 | HttpOnly (+ 근본 대책은 XSS 자체 차단: CSP) |
| 네트워크 도청 | 공용 와이파이 등에서 HTTP 평문 트래픽을 가로채 쿠키 복사 | Secure (+ HSTS로 HTTP 접속 자체 제거) |
| CSRF | 악성 사이트가 사용자의 브라우저로 내 사이트에 위조 요청을 발사 — 쿠키가 자동 동봉됨 | SameSite=Lax 이상 (+ CSRF 토큰 병행) |
| 세션 고정·쿠키 덮어쓰기 | 탈취된 서브도메인이 상위 도메인 쿠키를 심어 세션을 조작 | __Host- 접두사 |
세션 쿠키라면 특별한 이유가 없는 한 이 레시피를 그대로 쓰면 됩니다.
Set-Cookie: session=<랜덤값>; Path=/; Secure; HttpOnly; SameSite=Lax
더 강하게 가려면 이름을 __Host-session으로 바꾸기만 하면 됩니다. 쿠키는 방어의 한 축일 뿐이므로, XSS를 원천에서 줄여 주는 CSP·HSTS 같은 응답 헤더가 함께 설정되어 있는지 보안 헤더 검사로 같이 점검하는 것을 권합니다.
실전 해부: Set-Cookie 한 줄 뜯어보기
실제 서비스에서 볼 법한 한 줄을 속성 단위로 읽어 보겠습니다.
Set-Cookie: __Host-session=9f2c1e...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=86400
__Host-session=9f2c1e...— 이름과 값.__Host-접두사 덕분에 브라우저가Secure·Path=/·Domain없음 조건을 강제 검증합니다. 값은 추측 불가능한 랜덤 토큰이어야 합니다.Path=/— 사이트 전체 경로에서 전송. 접두사 규칙상 필수입니다.Secure— HTTPS에서만 오갑니다. HTTP로 접속해도 이 쿠키는 절대 실리지 않습니다.HttpOnly— 페이지의 어떤 스크립트도 이 값을 읽을 수 없습니다. XSS가 터져도 쿠키 원본 탈취는 차단됩니다.SameSite=Lax— 다른 사이트에서 POST·iframe·이미지로 위조한 요청에는 붙지 않고, 사용자가 링크를 눌러 넘어올 때만 붙습니다.Max-Age=86400— 24시간 뒤 자동 만료되는 영구 쿠키. 이 속성이 없었다면 브라우저 종료 시 사라지는 세션 쿠키였을 것입니다.
이렇게 다섯 가지 속성이 모두 붙은 쿠키가 “교과서적” 세션 쿠키입니다. 운영 중인 사이트라면 쿠키 검사기로 실제 응답의 쿠키들을 나열해 빠진 속성이 없는지 확인하고, 프레임워크 기본값(예: 세션 미들웨어의 secure·httpOnly옵션)을 명시적으로 켜 두세요.
자주 묻는 질문
쿠키를 삭제하면 로그인이 풀리는 이유는 무엇인가요?
HttpOnly를 켜면 XSS가 완전히 막히나요?
SameSite=Lax와 Strict 중 무엇을 써야 하나요?
서드파티 쿠키가 차단되면 내 사이트 로그인도 깨지나요?
Domain 속성은 지정하는 것이 좋은가요, 생략하는 것이 좋은가요?
이 가이드와 함께 쓰면 좋은 도구
관련 가이드
- 필수 보안 헤더 설정 가이드(CSP·HSTS·X-Frame-Options)꼭 설정해야 할 보안 헤더와 각 헤더의 역할·권장 값·흔한 실수.
- CORS 에러 해결: Access-Control-Allow-Origin 완전 정리브라우저 CORS 에러가 나는 이유와 프리플라이트·자격증명·와일드카드 함정까지 상황별 해결법.