CORS와 도메인 정책

"Vercel에서는 되는데 운영에서 안 되는 이유"

by 제임스

"로컬에서는 잘 되는데 왜 배포하면 안 될까요?"


11년차 QA 엔지니어로서 수없이 들어본 질문이었습니다. 그때는 단순히 "환경 차이" 정도로만 이해했지만, 직접 개발을 하면서 그 "환경 차이"의 실체를 마주하게 되었습니다. 특히 CORS(Cross-Origin Resource Sharing)와 도메인 정책은 정말... 악몽 그 자체였습니다.


CORS란 대체 뭐길래...

처음 FastAPI로 백엔드를 만들고, React로 프론트엔드를 만들어 연결하려는데 브라우저 콘솔에 빨간 에러가 떴습니다.

Access to XMLHttpRequest at 'http://localhost:8000/api/users' from origin 'http://localhost:3000' has been blocked by CORS policy


"아니, 같은 localhost인데 왜 안 되는 거야?"

알고 보니 포트가 다르면 브라우저는 다른 출처(Origin)로 인식한다는 것이었습니다.

http://localhost:3000http://localhost:8000은 엄연히 다른 도메인이었던 것이죠.


환경별 CORS 설정의 지옥

1. 로컬 환경의 착각



처음엔 이렇게 간단하게 해결될 줄 알았습니다.


로컬에서는 잘 돌아갔습니다. "와, 생각보다 쉽네?" 라고 생각한 순간이 함정의 시작이었습니다.


2. Vercel 개발 환경의 복잡성

Vercel에 배포하니 상황이 복잡해졌습니다. Vercel은 브랜치별로 동적 URL을 생성합니다.

https://jamescompany-git-develop-james.vercel.app

https://jamescompany-abc123-james.vercel.app (PR 프리뷰)

https://api-jamescompany-git-develop-james.vercel.app



하지만 FastAPI의 CORSMiddleware는 와일드카드를 지원하지 않았습니다!


3. 와일드카드 CORS 구현하기

결국 커스텀 미들웨어를 만들어야 했습니다.


운영 환경의 새로운 도전: HTTPS와 보안 정책

1. HTTP에서 HTTPS로의 전환

운영 환경에서는 모든 것이 HTTPS여야 했습니다. Cloudflare를 통해 SSL을 적용했지만, 새로운 문제들이 나타났습니다.


2. Mixed Content 에러

프론트엔드는 HTTPS인데 백엔드 API를 HTTP로 호출하면 브라우저가 차단합니다.


3. HSTS(HTTP Strict Transport Security) 정책

Cloudflare에서 HSTS를 활성화하니 더 엄격해졌습니다.


Cookie 설정의 환경별 차이

인증 시스템을 구현하면서 쿠키 설정도 환경별로 달라야 했습니다.


1. 로컬 환경의 쿠키


2. SameSite 속성의 함정

개발 환경에서 SameSite=None을 사용하면 반드시 Secure=True여야 합니다. 하지만 로컬은 HTTP라서 Secure=True를 쓸 수 없습니다. 환경별로 다르게 설정해야 하는 이유였습니다.


3. 도메인 설정의 중요성

운영 환경에서 쿠키 도메인을 .jamescompany.kr로 설정하면,

www.jamescompany.kr

api.jamescompany.kr

admin.jamescompany.kr

모든 서브도메인에서 쿠키를 공유할 수 있습니다.


환경별 API 호출 설정


Preflight 요청의 이해

CORS 정책 때문에 브라우저는 실제 요청 전에 OPTIONS 메서드로 "이 요청 보내도 되나요?"라고 먼저 물어봅니다. 이게 Preflight 요청입니다.


Preflight가 발생하는 조건

GET, POST가 아닌 메서드 사용

Content-Type이 application/json인 경우

커스텀 헤더가 있는 경우


Preflight 최적화


실제 겪은 문제들과 해결책

1. "쿠키가 전송되지 않아요"

원인: withCredentials: true 설정 누락

해결: axios 인스턴스에 기본값으로 설정


2. "Vercel에서만 CORS 에러가 나요"

원인: 동적 URL 때문에 와일드카드 필요

해결: 커스텀 CORS 미들웨어 구현


3. "운영에서 쿠키가 저장 안 돼요"

원인: SameSite=Strict인데 도메인이 달라서

해결: API를 같은 도메인의 서브도메인으로 변경 (api.jamescompany.kr)


4. "로컬에서 HTTPS 테스트가 필요해요"

해결: mkcert를 사용한 로컬 HTTPS 설정


QA 관점에서의 테스트 전략

1. 환경별 CORS 테스트 체크리스트


2. 자동화 테스트 구현


CORS와 도메인 정책은 단순히 "설정 몇 줄 추가하면 되는" 문제가 아니었습니다. 환경별로 다른 보안 요구사항, 브라우저의 보안 정책, 쿠키 동작 방식 등 고려해야 할 것들이 정말 많았습니다.


"Vercel에서는 되는데 운영에서 안 돼요"라는 문제의 답은 대부분 여기에 있었습니다. 이제는 개발자가 이런 이슈를 리포트할 때, 단순히 "CORS 에러예요"가 아니라 구체적으로 어떤 환경에서 어떤 요청이 실패하는지 파악할 수 있게 되었습니다.


QA 엔지니어로서 이런 환경별 차이를 이해하고 나니, 테스트 케이스를 설계할 때도 훨씬 체계적으로 접근할 수 있게 되었습니다. "환경 차이"라는 추상적인 개념이 구체적인 설정과 코드로 이해되니, 더 정확한 이슈 분석과 재현이 가능해진 것이죠.


다음 편에서는 이런 환경별 설정 중에서도 가장 민감한 부분인 "보안 키 관리"에 대해 다뤄보겠습니다. JWT Secret을 Git에 올려버린 그날의 악몽을 함께 나누고 싶습니다...

keyword
이전 05화Monorepo에서 Multi-repo로