빌드노트
쿠키가 저장됐는데 다른 경로에서 로그인이 풀리면 Path를 확인한다
세션 쿠키가 저장돼 있어도 Path가 요청 URL에 맞지 않으면 서버에는 전송되지 않는다. 새 브라우저 컨텍스트에서 /account와 / 쿠키의 저장·요청·서버 수신을 비교하고, 기본 Path와 변경 뒤 중복 쿠키까지 확인해 적용 경로를 고르는 방법을 설명한다.
로그인 응답에서 세션 쿠키를 받았는데 /account 밖으로 이동하면 다시 비로그인처럼 보인다면, 저장된 쿠키의 Path와 실패한 요청의 URL을 먼저 비교한다. Path=/account인 쿠키는 /account/profile에는 보내지만 /나 /api/me에는 보내지 않는다. 쿠키가 브라우저에 남아 있어도 요청 경로에 따라 서버가 받는 값은 달라진다.
이때 응답의 Set-Cookie만으로 저장 성공을 판단하면 안 된다. 브라우저에 실제로 저장됐는지, 다음 요청에 포함됐는지, 서버가 받았는지를 나눠 보면 어디에서 빠졌는지 찾을 수 있다.
저장됐지만 요청에는 없는 경우
가짜 쿠키 하나를 발급하는 로컬 서버로 두 조건을 비교했다. Windows 11, Python 3.12.10, Playwright 1.59.0, Chromium 147.0.7727.15를 사용했다. 서버는 127.0.0.1에만 열었고, 조건마다 쿠키가 없는 새 브라우저 컨텍스트에서 시작했다. 기존 브라우저 세션은 읽지 않았다.
각 조건에서 /account/login 응답이 보낸 헤더다. 아래 두 줄은 서로 다른 실험의 응답이며, 값도 구분하기 위해 다르게 넣었다.
Set-Cookie: lab_session=account; Path=/account; HttpOnly; SameSite=Lax
Set-Cookie: lab_session=root; Path=/; HttpOnly; SameSite=Lax
두 쿠키 모두 브라우저 저장소에서 확인됐다. 이어 같은 호스트의 여러 경로를 열고, 브라우저의 요청 헤더와 서버가 받은 헤더를 대조했다. 두 기록은 일치했다. 다음은 비교에 필요한 경로와 Cookie 헤더만 추린 결과다. 실험용 쿼리 문자열은 생략했다.
Path=/account
/account/profile Cookie: lab_session=account
/ Cookie 헤더 없음
/accounting Cookie 헤더 없음
/api/me Cookie 헤더 없음
Path=/
/account/profile Cookie: lab_session=root
/ Cookie: lab_session=root
/accounting Cookie: lab_session=root
/api/me Cookie: lab_session=root
/account와 /account/에도 /account 쿠키가 전송됐다. 반면 /accounting은 앞부분의 글자가 같아도 적용 대상이 아니었다. RFC 6265의 경로 일치 규칙 (새 탭에서 열림)은 경로가 정확히 같거나, 하위 경로를 구분하는 / 경계가 있어야 한다고 정한다.
비교 기준은 주소창에 보이는 페이지가 아니라 쿠키를 받아야 하는 요청의 URL이다. /account/profile 페이지에서 같은 출처의 /api/me를 fetch로 호출했을 때도 /account 쿠키는 빠졌다. / 쿠키는 전송됐다. 화면 경로가 /account 아래라는 사실만으로 API 요청까지 그 쿠키를 받지는 않는다.
내 브라우저에서는 세 곳을 대조한다
Chrome에서 개발자 도구를 연 뒤 Network 기록을 켜고 로그인부터 다시 수행한다. 다른 경로로 이동할 때 기록이 지워진다면 Preserve log를 켠다. 다음 순서로 같은 쿠키를 찾는다.
- 로그인 응답: Network에서 해당 응답의
Set-Cookie를 읽는다. 쿠키 이름과 Path를 확인한다. 응답 헤더가 있다는 사실과 브라우저가 받아들였다는 사실은 별개다. - 저장소: Application → Storage → Cookies에서 해당 사이트를 고르고 같은 이름의 행을 찾는다. Domain과 Path, 만료 상태를 함께 본다. 같은 이름의 쿠키가 여러 행이면 Path도 각각 읽는다. Chrome의 쿠키 확인 안내 (새 탭에서 열림)
- 실패한 요청: Network에서 비로그인 결과를 받은 요청을 고른다. Request URL과 Request Headers의
Cookie에 그 이름이 있는지 확인하고, 서버 측에서도 같은 요청을 대조한다. 실제 세션 값은 로그에 그대로 남기지 말고 이름의 존재 여부만 확인한다.
저장소에 행이 없다면 Path에 따른 전송 제외를 확인한 것이 아니다. 응답 쿠키의 차단 사유와 만료 여부부터 살핀다. 행이 있고 /account/profile에는 실리지만 /api/me에는 빠진다면, 저장된 Path가 두 URL을 어떻게 가르는지 확인할 수 있다. Path에 맞는 요청에서도 빠지면 Domain, Secure, SameSite, 교차 출처 요청의 credentials 조건 등 다른 전송 조건을 조사한다. Cookie가 서버까지 도착했는데도 비로그인이라면 서버의 세션 조회·만료·인증 처리를 확인한다.
document.cookie의 빈 문자열만으로 저장 실패를 판단하지도 않는다. 이번 실험에서는 쿠키를 발급한 /account/login에서도 그 값이 비어 있었지만, 저장소에는 쿠키가 있었고 적용 경로의 요청에는 전송됐다. HttpOnly를 붙였기 때문이다. MDN의 HttpOnly 설명 (새 탭에서 열림)은 자바스크립트의 읽기를 막으면서 HTTP 요청에는 쿠키를 보낼 수 있다고 설명한다.
Path를 생략해도 전체 경로가 되지는 않는다
세 번째 조건에서는 같은 /account/login 응답에서 Path만 생략했다.
Set-Cookie: lab_session=default; HttpOnly; SameSite=Lax
브라우저에 저장된 Path는 /account였다. /account/profile에는 lab_session=default가 전송됐고 /와 /api/me에는 빠졌다. RFC 6265의 기본 경로 계산 (새 탭에서 열림)은 쿠키를 발급한 요청 URL을 기준으로 한다. 이 URL에서는 마지막 / 앞까지인 /account가 기본값이다. Path를 지우는 수정으로 사이트 전체에 적용될 것이라고 예상하면 같은 증상이 남을 수 있다.
세션을 쓰는 요청들이 속한 경로를 정한다
로그인 응답을 만드는 코드나 프레임워크의 세션 쿠키 설정에서 Path를 확인한다. 세션을 사용하는 요청이 모두 /account 아래라면 /account를 유지할 수 있다. 같은 호스트에서 /, /account, /api가 그 세션을 함께 써야 한다면 이 경로들을 포함하는 /를 명시하는 선택이 맞다. 다른 호스트로 쿠키를 보내야 하는 문제는 Path 변경만으로 해결되지 않는다.
위 헤더는 로컬 HTTP 실험값이다. 실제 HTTPS 서비스에서는 기존 Secure·HttpOnly·SameSite 설정을 유지하면서 필요한 Path를 조정하고, 서버 응답으로 쿠키를 다시 발급한 뒤 같은 요청들을 확인한다. Path는 요청에 쿠키를 붙일 범위를 정하는 속성이지 권한을 격리하는 보안 경계가 아니다. 서버의 인증·권한 검사는 계속 필요하다. MDN의 Path 설명 (새 탭에서 열림)
이미 /account 쿠키가 있는 브라우저에서는 변경 뒤의 저장소도 확인해야 한다. 추가 실험에서 같은 이름으로 / 쿠키를 발급하자 기존 쿠키를 덮어쓰지 않고 두 행이 남았다. /account/profile 요청에는 다음처럼 두 값이 함께 왔다.
Cookie: lab_session=account; lab_session=root
RFC 6265의 저장 규칙 (새 탭에서 열림)은 이름·도메인·경로가 같은 쿠키를 교체한다. Path가 달라진 쿠키가 기존 것을 자동으로 없애는 것은 아니다. 서버가 어느 값을 선택할지 순서에 기대지 말고 (새 탭에서 열림), 이전 쿠키의 이름·Domain 범위·Path에 맞춰 만료시키는 처리도 함께 확인한다. 이번에는 같은 호스트에서 Domain을 생략한 채 lab_session=; Path=/account; Max-Age=0; HttpOnly; SameSite=Lax를 Set-Cookie로 보냈다. 그 뒤에는 / 행 하나만 남았고 /account/profile에서도 lab_session=root 하나만 받았다.
직접 확인한 범위는 같은 호스트의 로컬 HTTP에서 가짜 쿠키가 저장되고 전송되는 과정이다. 실제 로그인 성공, 운영 세션의 유효성, HTTPS·다른 호스트·교차 사이트 환경, 다른 브라우저의 동작은 검증하지 않았다. 이 비교로 판단할 수 있는 것은 쿠키 저장 실패와 Path에 따른 요청 제외의 차이다.