프록시(Proxy)와 CORS

Jina·2025년 12월 18일

웹 개발을 하다 보면 "CORS 에러가 발생했다"는 메시지를 마주하게 된다. 이 문제를 해결하기 위해 많은 개발자들이 프록시(Proxy)를 사용한다. CORS가 무엇인지, 왜 발생하는지, 그리고 프록시를 통해 어떻게 해결하는지 알아보자.


🔒 CORS(Cross-Origin Resource Sharing)란?

CORS는 "교차 출처 리소스 공유"라는 의미이다. 간단히 말해, 한 출처(Origin)에서 다른 출처의 리소스에 접근할 때 적용되는 보안 정책이다.

🎯 출처(Origin)의 정의

출처는 프로토콜, 도메인, 포트 세 가지 조합으로 정의된다.

https://example.com:3000
│        │              │
프로토콜  도메인         포트

예를 들어, 다음은 모두 다른 출처이다.

  • https://example.com (포트 없음)
  • https://example.com:3000 (포트 3000)
  • http://example.com (프로토콜이 http)
  • https://api.example.com (서브도메인이 다름)

⚠️ CORS 에러가 발생하는 이유

브라우저는 보안상의 이유로 같은 출처 정책(Same-Origin Policy)을 강제한다. 예를 들어:

프론트엔드: https://myapp.com
API 서버: https://api.example.com

→ CORS 에러 발생!

프론트엔드에서 다른 출처의 API로 요청을 보내면 브라우저가 이를 차단한다. 이는 악의적인 웹사이트가 사용자의 데이터에 접근하는 것을 방지하기 위함이다.


🌉 프록시(Proxy)란?

프록시는 "중개자" 또는 "대리자"라는 의미이다. 웹에서 프록시는 클라이언트와 서버 사이에 위치하여 요청과 응답을 중개한다.

💡 프록시가 CORS를 해결하는 원리

┌─────────────────────────────────────┐
│   브라우저 (클라이언트)              │
│   출처: https://myapp.com           │
└──────────────────┬──────────────────┘
                   │
                   ↓ (같은 출처로 요청)
┌──────────────────────────────────────┐
│   프록시 서버                        │
│   출처: https://myapp.com:3000      │
│   (같은 도메인, 다른 포트)          │
└──────────────────┬───────────────────┘
                   │
                   ↓ (서로 다른 출처로 요청)
┌──────────────────────────────────────┐
│   실제 API 서버                      │
│   출처: https://api.example.com      │
└──────────────────────────────────────┘

프록시 서버가 브라우저와 같은 출처에 있으면, 브라우저 입장에서는 같은 출처로 요청하는 것이다. 따라서 CORS 에러가 발생하지 않는다.


⚙️ 프록시 설정 방법

1. package.json을 이용한 간단한 프록시 (Create React App)

Create React App 프로젝트라면 package.json에 한 줄만 추가하면 된다.

{
  "proxy": "https://api.example.com"
}

이제 프론트엔드에서 /api로 요청하면 자동으로
https://api.example.com/api로 포워딩된다.

// 브라우저에서
fetch('/api/users')
  .then(res => res.json())
  .then(data => console.log(data))

2. http-proxy-middleware를 이용한 상세 설정

더 복잡한 설정이 필요하면 http-proxy-middleware를 사용할 수 있다. src/setupProxy.js파일을 생성한다.

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'https://api.example.com',
      changeOrigin: true,
      pathRewrite: {
        '^/api': '' // '/api/users' → '/users'로 변환
      }
    })
  );
};

3. 개발 서버 직접 설정 (Webpack, Vite 등)

Vite를 사용한다면 vite.config.js에서

export default {
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
}

4. 환경별 프록시 설정

실제 프로젝트에서는 개발, 테스트, 운영 환경마다 다른 API 서버를 가리킬 수 있다.

const API_BASE_URL = process.env.NODE_ENV === 'development' 
  ? 'http://localhost:3001' 
  : 'https://api.example.com';

const response = await fetch(`${API_BASE_URL}/users`);

🔍 CORS 문제를 해결하는 다른 방법

1. 서버에서 CORS 헤더 설정

서버에서 적절한 CORS 헤더를 설정하면 브라우저가 요청을 허용한다.

// Node.js/Express 예제
const express = require('express');
const cors = require('cors');

app.use(cors({
  origin: 'https://myapp.com',
  credentials: true
}));

2. JSONP(JSON with Padding)

오래된 방식이지만 여전히 사용되기도 한다. 하지만 보안 측면에서 권장되지 않는다.

3. 백엔드 프록시

프론트엔드 프록시 대신 백엔드에서 외부 API를 호출하고, 프론트에서는 백엔드만 호출한다.

프론트엔드 → 같은 서버의 백엔드 → 외부 API

이 방식이 가장 안전하고 권장된다.


⚖️ 프록시 vs CORS 헤더 설정: 언제 어떤 것을 쓸까?

상황추천 방법이유
개발 단계, 외부 API 테스트프록시빠르고 간단
본인 서버의 APICORS 헤더 설정원본 해결, 더 안전
제3의 외부 API백엔드 프록시보안과 유연성
프로덕션 환경백엔드 프록시가장 안전

⚡ 주의사항

🚧 프록시의 한계

프록시는 개발 환경에서만 작동한다. 프로덕션에 배포되면 프록시가 작동하지 않으므로 반드시 다른 해결책이 필요하다.

🔐 보안 고려사항

프록시를 통해 민감한 데이터(API키 등)를 숨길 수 있지만, 프론트엔드 코드는 여전히 노출된다. 중요한 인증 정보는 반드시 백엔드에서 관리해야 한다.

// ❌ 위험: API 키가 프론트엔드에 노출
const API_KEY = 'sk_live_xxxx';

// ✅ 안전: 백엔드를 통해 관리
fetch('/api/internal/users'); // 백엔드가 API 키를 사용

🎯 결론

CORS는 웹의 보안을 지키는 중요한 메커니즘이다. 프록시는 개발 단계에서 편리한 도구이지만, 완전한 해결책은 아니다. 상황에 맞게 프록시, CORS 헤더 설정, 백엔드 프록시를 적절히 조합하여 사용하면 안전하고 효율적인 웹 애플리케이션을 만들 수 있다.

개발할 때는 프록시로 빠르게 테스트하고, 프로덕션 배포 전에는 반드시 CORS 설정이나 백엔드 프록시로 전환하는 것을 잊지 말자.

profile
즐겁게 코딩하고 공부해요🍀

0개의 댓글