
처음 백엔드 코드를 AWS 클러스터에 배포하고 S3에 배포한 프론트랑 연결하다가 마주친 CSP 에러!
반갑당
프론트 이미지 빌드할때 API_BASE_URL을 같이 빌드하니 BE로 요청은 가는데 CSP 에러 때문에 에러 발생.
| 항목 | 내용 |
|---|---|
| 문제 | S3에 배포된 프론트엔드에서 백엔드 API 호출이 완전히 차단됨 |
| 근본 원인 | Content Security Policy(CSP)에 백엔드 도메인이 허용되지 않음 |
| 상태 | ✅ 해결됨 |
| 심각도 | High (서비스 불가) |
npm run dev)| 항목 | 로컬 개발 환경 | S3 배포 환경 |
|---|---|---|
| 프론트엔드 URL | localhost:4180 | s3-bucket-url/AAA |
| 백엔드 호출 방식 | Vite 프록시 (/api → 백엔드) | 직접 호출 (https://api-AAA.com) |
| CSP 적용 | 개발 모드 (느슨함) | 빌드된 HTML의 엄격한 CSP |
| 단계 | 활동 내용 |
|---|---|
| 문제 보고 | "로컬에서는 되는데 S3에서는 백엔드 호출이 안 됨" |
| 초기 가설 | CORS 에러로 추정 → 하지만 Network 탭에 요청 자체가 없음 확인 |
| 환경 분석 | .env.development와 .env.production 확인 → 환경 변수명 불일치 발견 |
| 빌드 검증 | 빌드 명령어 확인: VITE_API_BASE_URL=... 환경 변수로 빌드 → API URL은 정상 주입됨 |
| dist 분석 | dist/assets/*.js 파일에서 https://api-AAA 확인 → API URL 정상 |
| CSP 발견 | index.html의 CSP 메타 태그 확인 → connect-src에 백엔드 도메인 누락 발견 |
| 해결 적용 | CSP의 connect-src에 https://*.AAA 추가 |
| 검증 | 재빌드 및 재배포 필요 (사용자 측에서 확인 예정) |
| # | 질문 | 답변 |
|---|---|---|
| 1 | 왜 S3에서 백엔드 호출이 안 되는가? | 브라우저가 요청을 차단함 |
| 2 | 왜 브라우저가 요청을 차단하는가? | Content Security Policy 위반 |
| 3 | 왜 CSP 위반이 발생하는가? | connect-src에 백엔드 도메인이 없음 |
| 4 | 왜 백엔드 도메인이 없는가? | CSP 설정 시 백엔드 도메인을 고려하지 않음 |
| 5 | 왜 로컬에서는 작동했는가? | Vite 개발 서버의 프록시가 CSP를 우회함 |
🎯 근본 원인:
index.html의 Content Security Policy에서 connect-src 지시어가 'self' https://*.paddle.com만 허용하도록 설정되어 있었고, 백엔드 API 도메인(https://*.AAA)이 포함되지 않아 브라우저가 요청을 원천 차단했음.
<meta http-equiv="Content-Security-Policy"
content="connect-src 'self' https://*.paddle.com;" />
connect-src: XMLHttpRequest, Fetch API, WebSocket 등 네트워크 요청을 제어'self': 현재 origin(S3 도메인)만 허용https://*.paddle.com: Paddle 결제 도메인만 허용api-dev.skuberplus.com은 허용되지 않음// vite.config.ts
server: {
proxy: {
'/api': {
target: 'https://api-AAA',
changeOrigin: true,
},
},
}
/api 요청을 백엔드로 전달localhost:4180)으로 요청'self'에 해당하여 허용됨// src/api/client.ts
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
// → "https://api-dev.AAA"
export const apiClient = axios.create({
baseURL: API_BASE_URL, // 직접 호출
});