티스토리 뷰

ETC

Cross-Origin Resource Sharing (CORS)

hjkang 2026. 2. 3. 20:58

CORS란?

Cross-Origin Resource Sharing - 다른 출처의 리소스를 공유하는 것을 브라우저가 막는 보안 정책

 

 

출처(Origin)란?

- 프로토콜, 도메인, 포트 세 가지 중 하나라도 다른 경우 다른 출처

https://example.com:3000/api/users
└─┬─┘   └────┬────┘ └┬┘
프로토콜   도메인   포트

 

왜 CORS 에러가 날까?

- CORS는 브라우저의 정책으로, Postman이나 서버에서는 문제 없이 동작

// 브라우저에서 실행
fetch('https://api.example.com/data')
  .then(res => res.json())
  .then(console.log);

// CORS 에러!
// Access to fetch at 'https://api.example.com/data' from origin 
// 'https://myapp.com' has been blocked by CORS policy

 

해결 방법

1. 서버에서 CORS 허용 (정석)

const express = require('express');
const cors = require('cors');
const app = express();

// 모든 출처 허용 (개발용)
app.use(cors());

// 특정 출처만 허용 (프로덕션)
app.use(cors({
  origin: 'https://myapp.com',
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

 

직접 헤더 설정

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://myapp.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', 'true');
  
  // Preflight 요청 처리
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  
  next();
});

 

2. 개발 환경에서 프록시 사용

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

// 이제 /api/users로 요청하면 https://api.example.com/users로 전달
fetch('/api/users'); // CORS 문제 없음

 

// nuxt.config.js
export default defineNuxtConfig({
  nitro: {
    devProxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true
      }
    }
  }
})

 

자주 하는 실수

1. * 와 credentials 함께 사용

// 에러 발생
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', 'true');

// 특정 도메인 명시
res.header('Access-Control-Allow-Origin', 'https://myapp.com');
res.header('Access-Control-Allow-Credentials', 'true');

 

 

2. Preflight 요청 처리 X

// OPTIONS 요청 처리 안 함
app.post('/api/users', (req, res) => {
  // POST만 처리
});

// OPTIONS 요청도 처리
app.options('/api/users', (req, res) => {
  res.sendStatus(200);
});

app.post('/api/users', (req, res) => {
  // POST 처리
});

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함