본문으로 건너뛰기
개발 머꼬
개발 노트보안
hohyeon.dev26

서브도메인 하나가 탈취되면 전체 세션이 위험해지는 구조를 정리한 과정

  • #Auth
  • #Engineering Note
  • #보안

문제 발생

세션 쿠키를 이렇게 심고 있었습니다.

Set-Cookie: session=...; Domain=.example.com; Path=/

편했습니다 — 모든 서브도메인이 같은 세션을 봤으니까요. 그런데 정적 사이트 하나를 외부 서비스에 붙이면서 질문이 생겼습니다. 그 서브도메인이 침해되면 세션 쿠키를 읽거나 덮어쓸 수 있지 않나?

원인 분석

쿠키의 격리 단위는 origin이 아닙니다. Domain 속성을 붙이면 그 도메인의 모든 서브도메인에 쿠키가 전송되고, 반대로 어떤 서브도메인이든 상위 도메인 쿠키를 덮어쓸 수 있습니다(쿠키 토싱). 게다가 쿠키는 포트로 구분되지 않습니다.

브라우저는 이 문제를 위해 이름 접두사를 정의했습니다. MDN 설명 그대로입니다.

  • __Secure- — 보안 페이지(HTTPS)에서 Secure 속성과 함께 설정되어야 합니다.
  • __Host-Secure와 함께 HTTPS에서 설정되어야 하고, Domain 속성이 없어야 하며, Path/여야 합니다. 그 결과 이 쿠키는 자신을 설정한 호스트에만 전송되고 그 도메인의 다른 호스트에는 가지 않으며, origin을 보안 경계로 취급합니다.

속성 자체의 역할도 명확합니다 — Securehttps: 스킴 요청에만 전송되게 해 중간자 공격에 강하게 하고, HttpOnlyJavaScript의 document.cookie 접근을 막아 XSS 피해를 줄이며, SameSite교차 사이트 요청에 쿠키가 실릴지 제어해 CSRF를 막습니다.

해결 방안

  1. 호스트에 묶여야 하는 쿠키는 __Host-를 씁니다.
Set-Cookie: __Host-session=...; Secure; HttpOnly; SameSite=Lax; Path=/

Domain이 없다는 것이 요건이라 실수로 넓힐 수 없습니다.

  1. 서브도메인 공유가 진짜 요구인지 먼저 확인합니다. MEOKKO는 meokko.com과 5개 서브도메인이 하나의 세션을 공유해야 해서 Domain이 필요합니다 — 이 경우 __Host-는 쓸 수 없고, 대신 어떤 서브도메인도 신뢰 경계 밖에 두지 않는다는 운영 원칙이 함께 가야 합니다. 외부 서비스에 서브도메인을 내주는 순간 이 전제가 깨집니다.

  2. 속성 네 가지를 항상 함께 정합니다. Secure, HttpOnly, SameSite, 그리고 Path. 하나라도 기본값에 맡기면 나중에 이유를 설명할 수 없습니다.

  3. SameSite=None을 습관적으로 쓰지 않습니다. MDN 설명대로 None은 교차 사이트 요청에도 전송되며 Secure가 필수입니다. 같은 등록 도메인의 서브도메인 사이라면 Lax로 충분합니다.

  4. JS가 읽어야 하는 값과 세션을 분리합니다. 테마·언어 같은 값은 HttpOnly 없이, 세션 토큰은 반드시 HttpOnly로 둡니다. 하나의 쿠키가 두 역할을 하면 결국 보호가 약한 쪽에 맞춰집니다.

  5. 인증 라이브러리의 기본값을 확인만 하고 넘기지 않습니다. 쿠키 이름, 도메인, SameSite는 배포 환경에서 실제 응답 헤더를 열어 확인합니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.