서브도메인 하나가 탈취되면 전체 세션이 위험해지는 구조를 정리한 과정
문제 발생
세션 쿠키를 이렇게 심고 있었습니다.
Set-Cookie: session=...; Domain=.example.com; Path=/편했습니다 — 모든 서브도메인이 같은 세션을 봤으니까요. 그런데 정적 사이트 하나를 외부 서비스에 붙이면서 질문이 생겼습니다. 그 서브도메인이 침해되면 세션 쿠키를 읽거나 덮어쓸 수 있지 않나?
원인 분석
쿠키의 격리 단위는 origin이 아닙니다. Domain 속성을 붙이면 그 도메인의 모든 서브도메인에 쿠키가 전송되고, 반대로 어떤 서브도메인이든 상위 도메인 쿠키를 덮어쓸 수 있습니다(쿠키 토싱). 게다가 쿠키는 포트로 구분되지 않습니다.
브라우저는 이 문제를 위해 이름 접두사를 정의했습니다. MDN 설명 그대로입니다.
__Secure-— 보안 페이지(HTTPS)에서Secure속성과 함께 설정되어야 합니다.__Host-—Secure와 함께 HTTPS에서 설정되어야 하고,Domain속성이 없어야 하며,Path는/여야 합니다. 그 결과 이 쿠키는 자신을 설정한 호스트에만 전송되고 그 도메인의 다른 호스트에는 가지 않으며, origin을 보안 경계로 취급합니다.
속성 자체의 역할도 명확합니다 — Secure는 https: 스킴 요청에만 전송되게 해 중간자 공격에 강하게 하고, HttpOnly는 JavaScript의 document.cookie 접근을 막아 XSS 피해를 줄이며, SameSite는 교차 사이트 요청에 쿠키가 실릴지 제어해 CSRF를 막습니다.
해결 방안
- 호스트에 묶여야 하는 쿠키는
__Host-를 씁니다.
Set-Cookie: __Host-session=...; Secure; HttpOnly; SameSite=Lax; Path=/Domain이 없다는 것이 요건이라 실수로 넓힐 수 없습니다.
-
서브도메인 공유가 진짜 요구인지 먼저 확인합니다. MEOKKO는
meokko.com과 5개 서브도메인이 하나의 세션을 공유해야 해서Domain이 필요합니다 — 이 경우__Host-는 쓸 수 없고, 대신 어떤 서브도메인도 신뢰 경계 밖에 두지 않는다는 운영 원칙이 함께 가야 합니다. 외부 서비스에 서브도메인을 내주는 순간 이 전제가 깨집니다. -
속성 네 가지를 항상 함께 정합니다.
Secure,HttpOnly,SameSite, 그리고Path. 하나라도 기본값에 맡기면 나중에 이유를 설명할 수 없습니다. -
SameSite=None을 습관적으로 쓰지 않습니다. MDN 설명대로None은 교차 사이트 요청에도 전송되며Secure가 필수입니다. 같은 등록 도메인의 서브도메인 사이라면Lax로 충분합니다. -
JS가 읽어야 하는 값과 세션을 분리합니다. 테마·언어 같은 값은
HttpOnly없이, 세션 토큰은 반드시HttpOnly로 둡니다. 하나의 쿠키가 두 역할을 하면 결국 보호가 약한 쪽에 맞춰집니다. -
인증 라이브러리의 기본값을 확인만 하고 넘기지 않습니다. 쿠키 이름, 도메인, SameSite는 배포 환경에서 실제 응답 헤더를 열어 확인합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.