웹앱 로그인 유지 설계 체크리스트: 쿠키·CORS·CSRF

핵심 요약
로그인 성공 응답보다 이후 요청에서 인증 정보가 안전하게 저장·전송·검증되는 전체 흐름을 설계해야 하며, 쿠키 속성과 CORS·CSRF 방어를 함께 확인해야 합니다.

검수 범위
브라우저 기반 웹앱의 쿠키 세션 또는 refresh token 구성을 다루며, 특정 프레임워크에 종속된 완성 코드를 제시하지 않습니다.

웹앱 로그인은 아이디와 비밀번호가 맞아 200 응답을 받는 순간 끝나지 않습니다. 브라우저가 인증 정보를 저장하고, 필요한 요청에만 전송하고, 서버가 만료와 위조를 검증하고, 로그아웃 때 폐기하는 전체 흐름이 정상이어야 합니다. 개발 환경에서는 되는데 운영 도메인에서만 로그인이 풀린다면 쿠키와 출처 정책을 단계별로 확인해야 합니다.

먼저 인증 방식을 한 문장으로 설명하기

팀 문서에 “서버 세션 ID를 HttpOnly 쿠키로 보낸다” 또는 “짧은 access token과 회전하는 refresh token을 사용한다”처럼 현재 방식을 한 문장으로 적습니다. access token, refresh token, 서버 세션을 섞어 쓰면서 각 값의 책임이 불분명하면 만료와 로그아웃 동작도 흔들립니다.

쿠키 속성 점검

  • HttpOnly: 브라우저 JavaScript에서 읽을 필요가 없는 세션 토큰은 HttpOnly를 고려합니다.
  • Secure: 운영 HTTPS에서만 전송해야 하는 인증 쿠키에 사용합니다.
  • SameSite: same-site와 cross-site 배치에 맞춰 Lax, Strict, None을 선택합니다. None은 Secure 요구와 함께 확인합니다.
  • Domain: 필요 이상으로 넓은 상위 도메인에 공유하지 않습니다.
  • Path: 토큰이 필요한 경로 범위만 사용합니다.
  • 만료: 브라우저 세션 종료와 서비스 로그인 유지 정책을 구분합니다.

쿠키 값 전체를 일반 로그에 남기지 말고, 추적이 필요하면 원본을 복구할 수 없는 짧은 식별값을 별도로 사용합니다.

CORS와 credentials 함께 보기

프론트와 API의 출처가 다르면 브라우저의 CORS 검사가 적용됩니다. 쿠키를 포함할 요청은 프론트 요청 옵션과 서버 응답 설정이 함께 맞아야 합니다. credentials를 사용하는 응답에서 모든 출처를 뜻하는 와일드카드를 그대로 허용할 수 없으며, 신뢰하는 출처를 정확히 반영해야 합니다.

서버 간 요청 도구에서 성공한다고 브라우저에서도 성공하는 것은 아닙니다. 브라우저 개발자 도구의 Network와 Application 또는 Storage 화면에서 다음을 구분해 봅니다.

  1. 로그인 응답에 Set-Cookie가 있는가?
  2. 브라우저가 쿠키를 차단했다면 이유가 표시되는가?
  3. 후속 API 요청의 Cookie 헤더에 포함되는가?
  4. preflight 요청과 실제 요청의 허용 출처가 일치하는가?

CSRF 방어를 빠뜨리지 않기

브라우저가 쿠키를 자동으로 전송하는 구조에서는 공격 사이트가 사용자의 브라우저를 이용해 상태 변경 요청을 보내는 CSRF 위험을 고려해야 합니다. SameSite만으로 모든 배치를 해결할 수 있다고 가정하지 말고 프레임워크의 CSRF 토큰, Origin 또는 Referer 검증, 중요한 작업의 재인증을 서비스 구조에 맞게 적용합니다.

access token 만료와 refresh 동시 요청

여러 API가 동시에 401을 받으면 refresh 요청도 여러 번 실행될 수 있습니다. refresh token rotation을 사용한다면 첫 요청이 토큰을 교체한 뒤 나머지 요청이 이전 토큰을 보내 실패할 수 있습니다. 클라이언트에서는 갱신 작업을 한 번만 실행하고 대기 중인 요청이 같은 결과를 사용하도록 직렬화하는 방식을 검토합니다.

서버에서는 이전 refresh token의 재사용을 어떻게 탐지하고, 네트워크 오류로 응답만 유실된 경우를 어떻게 처리할지 정책이 필요합니다. 무한 재시도 대신 실패 횟수와 최종 로그아웃 조건을 정합니다.

세션 고정과 토큰 교체

로그인 전후에 같은 세션 식별자를 계속 사용하면 세션 고정 공격에 노출될 수 있습니다. 로그인 성공, 권한 상승, 비밀번호 변경 같은 보안 경계에서 세션을 새로 발급할지 확인합니다. 로그아웃은 브라우저 쿠키만 지우는 것이 아니라 서버 세션 또는 refresh token도 더 이상 사용할 수 없게 해야 합니다.

운영 로그에 남길 정보

  • 요청 ID와 사용자 계정의 내부 식별자
  • 인증 실패 유형: 없음, 만료, 서명 실패, 폐기됨
  • 쿠키 원본이 아닌 세션 또는 토큰 레코드 식별자
  • 요청 출처와 필요한 경우 기기 세션 정보
  • refresh 성공·실패와 이전 토큰 재사용 탐지

비밀번호, 전체 JWT, refresh token, 세션 쿠키는 로그에 기록하지 않습니다.

반드시 재현할 테스트

상황 기대 결과
새로고침 허용된 유지 정책 안에서 로그인 상태 복원
access token 만료 한 번만 갱신하고 원래 요청 재개
refresh token 만료·폐기 루프 없이 로그인 화면으로 이동
여러 탭의 동시 401 토큰 갱신 충돌 없이 일관된 상태 유지
다른 허용 출처와 비허용 출처 CORS 정책에 맞게 허용 또는 차단
로그아웃 후 뒤로가기 보호 API와 민감 화면 재접근 차단

인증 문제를 “토큰 시간이 짧아서”라고 단정하기 전에 저장, 전송, 검증, 갱신, 폐기 다섯 단계를 같은 요청 ID로 따라가면 실제로 끊기는 지점을 찾기 쉽습니다.


검증 기준과 참고 자료

이 글은 2026-09-08에 아래 공식 문서와 공개 기술 문서를 기준으로 내용과 용어를 다시 검수했습니다. 제품 버전과 기기 제조사에 따라 화면 이름은 달라질 수 있으므로 실제 화면과 공식 문서를 함께 확인하세요.

관련 글