웹 개발
로그인 쿠키에 SameSite를 설정하지 않으면 생기는 일
SameSite 속성 없이 쿠키를 발급하면 cross-origin 요청에서 쿠키가 붙지 않는다. Lax, Strict, None의 차이와 언제 무엇을 써야 하는지 정리했다.
로그인 기능을 만들 때 쿠키에 SameSite를 제대로 설정하지 않으면 나중에 이상한 현상이 생긴다. 프론트엔드와 API가 같은 도메인이면 괜찮다가, 서브도메인이 다르거나 Vercel 배포처럼 cross-origin 환경이 되면 쿠키가 아예 전달되지 않는다.
SameSite가 뭔지
SameSite는 쿠키가 cross-site 요청에 포함될지를 결정하는 속성이다. 세 가지 값이 있다.
| 값 | 동작 |
|---|---|
Strict | 동일 사이트 요청에만 쿠키 포함 |
Lax | 동일 사이트 + 외부에서 들어오는 GET 탑레벨 내비게이션에 포함 |
None | 모든 cross-site 요청에 포함 (반드시 Secure와 함께 써야 함) |
Chrome 80 이후로 SameSite를 명시하지 않으면 Lax가 기본값으로 적용된다. 이전에는 None이 기본이었다.
어떤 값을 써야 하나
일반적인 웹 앱이라면 Lax를 쓴다. 외부 링크를 타고 들어와서 로그인 상태가 유지되어야 하고, CSRF 위험도 어느 정도 막을 수 있다.
프론트엔드와 API 서버의 도메인이 다른 경우(예: app.example.com → api.otherdomain.com)에는 None을 써야 하고, 반드시 HTTPS가 필요하다.
// Node.js / Express 예시
res.cookie('session', token, {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 7 * 24 * 60 * 60 * 1000,
});
httpOnly: true를 빠뜨리면 JavaScript에서 쿠키를 읽을 수 있어서 XSS 공격에 취약해진다.
디버깅 방법
Chrome DevTools의 Application 탭 → Cookies에서 각 쿠키의 SameSite 값을 확인할 수 있다. SameSite=None인데 Secure 플래그가 없으면 브라우저가 무시한다.
cross-origin fetch에서 쿠키를 포함시키려면 요청 시에도 설정이 필요하다.
fetch('https://api.example.com/me', {
credentials: 'include',
});
서버에서도 CORS 응답 헤더에 Access-Control-Allow-Credentials: true와 구체적인 Access-Control-Allow-Origin(와일드카드 * 불가)을 설정해야 한다. 이 두 가지 중 하나라도 빠지면 쿠키가 전달되지 않는다.