트러블슈팅 - 크로스 플랫폼 배포 시 HttpOnly RefreshToken이 전달되지 않는 문제

J_log·2025년 5월 17일
0
post-thumbnail

프로젝트 개요

현재 GigSync라는 인디밴드 커뮤니티 웹 어플리케이션을 개발하고 있다.

  • 프론트엔드 : Vite + React (localhost:5173)
  • 백엔드 : Spring Boot (localhost:8080)
  • 인증 방식 : JWT + Refresh Token (HttpOnly Cookie)

로컬 환경에서는 아무 문제 없이 RefreshToken이 쿠키로 잘 전달되고 인증이 매끄럽게 동작했다.
그러나 EC2에 프론트와 백엔드를 각각 배포하면서 문제가 발생했다.

발생한 문제 : 로그인 직후 로그아웃됨

프론트 EC2에서는 로그인 요청을 정상적으로 보내고, 백엔드 EC2에서는 RefreshToken을 Set-Cookie 헤더에 담아 응답했음에도 불구하고, 쿠키가 클라이언트에 저장되지 않았다.
결과적으로 인증 상태가 유지되지 않아 로그인 직후 자동 로그아웃되는 현상이 발생했다.

원인분석 : 크로스 도메인 + 보안 정책

  1. Same-Origin Policy와 크로스 도메인
    브라우저는 보안상 출처(origin)가 다른 경우 쿠키를 자동으로 저장하거나 전송하지 않는다.

    항목프론트백엔드Same-Origin인가?
    로컬http://localhost:5173http://localhost:8080X (포트 다름)
    EC2 배포http://FRONT_IPhttp://BACK_IPX (도메인 다름)
  • 포트가 다르거나 도메인이 다르면 Same-Origin이 아니다.
  1. Set-Cookie의 보안 속성
    백엔드가 보낸 쿠키가 브라우저에 저장되려면 아래 조건을 만족해야 한다.

    속성설명테스트 환경에서 주의할 점
    HttpOnly자바스크립트로 접근 불가로그인 보안 향상
    SecureHTTPS에서만 동작로컬이나 HTTP EC2에서는 작동 안 함
    SameSite=None크로스 사이트 요청 허용Secure가 반드시 같이 설정되어야 함

    즉, SameSite=None; Secure 조합은 HTTPS가 아니면 무효하다.

해결 방법

테스트 환경에서의 임시 해결(프론트 + 백엔드를 단일 EC2에 배포)

  • NGINX 또는 Caddy 등으로 Reverse Proxy를 구성하여 하나의 도메인 또는 포트로 동작하게 한다.
  • 로컬처럼 동일 Origin이 되므로 쿠키가 정상 동작함

실제 서비스 운영 시 해결 방안

  1. 도메인 구입 및 HTTPS 적용
    • SSL 인증서로 HTTPS 적용
    • Secure 속성이 붙은 쿠키도 정상 작동
  2. 백엔드 응답 헤더 설정
ResponseCookie.from("refreshToken", token)
    .httpOnly(true)
    .secure(true) // HTTPS 환경에서만 작동
    .sameSite("None") // 크로스 도메인 허용
    .path("/")
    .build();
  1. 프론트엔드 요청 시 설정
axios.post('https://api.gigsync.com/login', data, {
  withCredentials: true // 반드시 설정
});

쿠키 전달 문제 점검 체크리스트

체크 항목확인 내용
withCredentials 설정 여부프론트 axios/fetch에서 반드시 포함
Set-Cookie에 SameSite 포함 여부백엔드 쿠키 설정 확인
HTTPS 환경 여부Secure 쿠키는 HTTPS에서만 유효
도메인/서브도메인 설정크로스 도메인 여부에 따라 SameSite 고려

끝으로..

테스트 환경에서는 동일 EC2에 프론트와 백엔드를 배치하여 문제를 해결했지만, 서비스 확장성보안성을 고려하면 도메인을 이용한 HTTPS 기반의 분리 배포가 필수이다. HttpOnly Cookie 기반 인증은 보안상 유리하지만, 크로스 도메인 환경에서의 제약을 반드시 이해하고 맞춰줘야 한다는 걸 알 수 있었다.

0개의 댓글