본문으로 건너뛰기
yutils

SameSite 쿠키와 CSRF — Lax·Strict·None 의 진짜 의미

SameSite 가 2020 년 CSRF 방어를 어떻게 바꿨는지, Lax/Strict/None 의 차이, Secure 가 필요한 시점, 3rd-party 쿠키 폐기, SameSite 외에 여전히 필요한 것.

약 8분 읽기

2020 년 Chrome 80 이 모든 쿠키의 SameSite 기본값을 Lax 로 바꾼 사건은 CSRF 방어 역사에서 가장 큰 변화였다. 그 전엔 CSRF 토큰 없으면 거의 모든 form POST 가 취약. 그 후엔 SameSite Lax 만으로 대부분 의 cross-site POST 가 자동 차단. 이 가이드는 Lax·Strict·None 의 정확한 차이, Secure 가 필요한 시점, 3rd-party 쿠키 폐기, SameSite 외에 여전히 박아야 하는 방어층을 정리한다.

SameSite 의 세 값

None — 모든 컨텍스트로 전송

Set-Cookie: token=abc; SameSite=None; Secure
  • cross-site 요청 (다른 도메인의 fetch, 이미지, iframe) 에도 쿠키 전송.
  • Secure 필수 — HTTPS 가 아닌 응답에 SameSite=None 박으면 브라우저가 무시.
  • 전형 사용: 3rd-party 위젯 (chat, 댓글, 광고 추적).

Lax — 안전한 top-level navigation 만

Set-Cookie: token=abc; SameSite=Lax
  • top-level GET 만 cross-site 쿠키 전송. 사용자가 다른 사이트 링크를 클릭해 우리 사이트로 오는 경우.
  • cross-site POST·fetch·iframe·이미지 등의 sub-request 는 쿠키 전송 X.
  • 2020+ 모든 모던 브라우저 기본값. 명시 안 하면 Lax.
  • 이게 CSRF 의 80% 를 자동 차단.

Strict — 같은 사이트 내부 요청만

Set-Cookie: token=abc; SameSite=Strict
  • 오직 같은 도메인 안에서 발생한 요청에만 쿠키 전송.
  • 외부 링크로 들어올 때 쿠키 X → 사용자가 우리 사이트 링크 클릭 → 로그인 풀린 것처럼 보임. 알림 메일·검색 결과에서 들어오는 사용자 UX 깨짐.
  • 내부 admin 패널, 결제 페이지 등 cross-site 진입이 불필요한 곳만.

"Same-site" 의 정확한 정의 — eTLD+1

SameSite 의 "site" 는 호스트가 아니라 eTLD+1 (effective Top-Level Domain + 1):

  • app.example.comapi.example.com — 같은 site (eTLD+1 = example.com).
  • example.comexample.org — 다른 site.
  • foo.github.iobar.github.io — 다른 site (PSL 의 github.io 가 effective TLD).

Public Suffix List (PSL) 가 결정. github.io·vercel.app 등이 PSL 에 등록돼 그 서브도메인끼리는 cross- site 로 취급. URL 파서 로 host 분해 후 eTLD+1 직관적으로 확인.

CORS 의 origin (scheme + host + port) 과 헷갈리지 말 것. SameSite 는 scheme 무관 + port 무관, 오직 eTLD+1 만.

Lax 의 예외 — POST 도 허용되는 케이스 (옛 동작)

Chrome 80 초기에는 SameSite=Lax 쿠키가 cross-site POST 에도 2 분간 전송됐다 ("Lax + POST"). 외부 결제 사이트에서 redirect 후 POST 하는 OAuth flow 등을 위해. 2021 년 이후 이 예외 거의 폐기됐고, OAuth 는 명시적으로 SameSite=None; Secure 또는 GET redirect 사용.

3rd-party 쿠키 폐기 (2024-2025)

Chrome 이 2024 년 1 월부터 3rd-party 쿠키를 점진적으로 차단 시작 (1% → 100%). Safari·Firefox 는 이미 기본 차단.

영향:

  • 광고 추적 — 가장 큰 영향. Privacy Sandbox (Topics API 등) 로 대체 시도.
  • SSO / Federated identity — Google Sign-In 등. FedCM (Federated Credential Management) API 가 대안.
  • 임베드 위젯 — Disqus 댓글, Stripe Checkout 등은 SameSite=None + 사용자 명시 동의 또는 별도 도메인 redirect flow.

2026 년 시점에 새 사이트 설계 시 — 3rd-party 쿠키에 의존하지 말 것. 별도 redirect flow + 자기 도메인 쿠키 패턴.

그 외 쿠키 속성

Secure

HTTPS 요청에만 전송. SameSite=None 과 함께 박는 게 필수.

HttpOnly

JS 의 document.cookie 로 읽기 X. XSS 한 번이면 모든 쿠키 탈취되던 문제를 막음. 인증 쿠키는 무조건 HttpOnly.

__Host- / __Secure- 접두사

  • __Secure-nameSecure 박힌 응답에서만 설정 가능.
  • __Host-name — 위 + Path=/ + Domain 속성 X. 정확히 한 호스트에만.

가장 안전한 인증 쿠키:

Set-Cookie: __Host-session=abc; Path=/; Secure; HttpOnly; SameSite=Lax

쿠키 파서 에 Set-Cookie 헤더를 붙이면 attribute 가 정확히 어떻게 파싱되는지 즉시 확인.

SameSite 만으로 CSRF 충분한가?

모던 브라우저 (2020+) + Lax 가 기본값 = cross-site POST·fetch 의 99% 는 자동 차단. 그래도 SameSite 가 모든 CSRF 를 막진 않는다:

  1. 같은 사이트 내 XSS — 우리 사이트 안 XSS 가 있으면 SameSite 무력. CSP 와 결합 필수.
  2. Subdomain takeoverblog.example.com 이 탈취되면 example.com 의 SameSite 쿠키 접근 가능.
  3. 구식 브라우저 — IE / 매우 오래된 안드로이드는 SameSite 미지원. 점유율 낮지만 0 은 아님.
  4. SameSite=None 의 의도적 사용 — cross-site 통합이 필요하면 SameSite 가 끄꺼져 있는 상태.

결론: SameSite 가 1 차 방어선. 추가로:

  • state-changing 요청에 CSRF 토큰 — 폼에 hidden input 또는 헤더로 동봉. 서버가 검증.
  • Origin / Referer 헤더 검증 — 더 가벼움. POST 요청의 Origin 헤더가 우리 도메인인지 확인.
  • Double-submit cookie pattern — 쿠키 값과 헤더 값이 일치하는지. JS 가 쿠키 읽어 헤더에 박는 방식.

현실 패턴 — 인증 쿠키 + API

# 1. 로그인 응답 — 가장 안전
Set-Cookie: __Host-session=eyJhbGc...;
  Path=/;
  Secure;
  HttpOnly;
  SameSite=Lax;
  Max-Age=86400

# 2. API 호출 시 cookie 자동 전송
GET /api/me
Cookie: __Host-session=eyJhbGc...

# 3. cross-site fetch 시도 (다른 사이트의 악성 코드)
fetch("https://example.com/api/transfer", {
  method: "POST",
  credentials: "include"
});
# → SameSite=Lax 가 POST 에 쿠키 차단 → 401

같은 사이트 안 일반 SPA → API 호출은 credentials: include 로 쿠키 동봉. cross-site 는 자동 차단.

흔한 함정

1. SameSite=None 만 박고 Secure 누락

브라우저가 무시 → 쿠키 설정 안 됨. Set-Cookie 응답이 있는데 다음 요청에 쿠키 안 옴 — 흔한 디버깅 시간 낭비.

2. dev 환경 (localhost http) 에서 SameSite=None

Secure 가 없으므로 동작 X. dev 는 SameSite=Lax 또는 미설정. 또는 Chrome 의 dev 모드 flag (chrome://flags) 로 임시 우회.

3. SameSite 만 믿고 CSRF 토큰 제거

같은 사이트 XSS 가 있으면 무력. 결제·계좌 변경 같은 high-stakes 동작 은 토큰 병행.

4. Strict 를 광범위 적용

외부 링크 클릭으로 들어오면 로그인 풀린 것처럼 보임. SEO 트래픽·이메일 링크 사용자 모두 UX 깨짐. Strict 는 매우 좁은 컨텍스트만.

5. eTLD+1 오해

api.example.comapp.example.com 가 같은 site. 한 곳의 쿠키가 다른 곳에도 전송. 둘이 다른 보안 컨텍스트라고 착각하면 안 됨.

6. 3rd-party 쿠키 의존 (2026)

Chrome 의 3rd-party 차단으로 끊김. 임베드 위젯은 redirect flow 로 설계 변경. SSO 는 FedCM 검토.

7. document.cookie 로 인증 쿠키 읽기

HttpOnly 권장 → JS 접근 불가. 인증 상태는 별도 API (예: /api/me) 로 확인.

요약

  • 2020+ 모든 모던 브라우저 기본값 = SameSite=Lax. cross-site POST·fetch 자동 차단.
  • None + Secure = cross-site 사용 (3rd-party 위젯). 점점 폐기 추세.
  • Strict 는 외부 진입 UX 깨짐 — 좁은 admin 패널만.
  • 가장 안전한 인증 쿠키 = __Host-name; Path=/; Secure; HttpOnly; SameSite=Lax.
  • SameSite 는 1 차 방어. CSP + CSRF 토큰 + Origin 검증 병행이 표준.
  • 3rd-party 쿠키는 2024-2025 폐기 진행 중. 새 시스템은 1st-party 만 가정.
가이드 목록으로