목차
1부에서는 CORS의 개념과 등장 배경, 프리플라이트 요청에 대해 알아보았습니다. 이제 2부에서는 실제 개발 환경에서 CORS를 어떻게 구현하고, 문제를 어떻게 디버깅하며, 보안을 고려한 모범 사례는 무엇인지 알아보겠습니다.
CORS 문제는 웹 개발에서 자주 마주치게 되는 난관 중 하나입니다. 하지만 체계적인 접근 방법과 올바른 구현 지식을 갖추면 쉽게 해결할 수 있습니다. 이 글을 통해 CORS 관련 문제를 효과적으로 해결하는 방법을 배워보세요!
⚙️ 다양한 환경에서 CORS 설정하기
CORS 문제를 해결하려면 서버 측 설정이 필요합니다. 주요 환경별 설정 방법을 알아봅시다:
Node.js + Express
Node.js의 Express 프레임워크에서는 cors
미들웨어를 사용하면 간단합니다:
const express = require('express');
const cors = require('cors');
const app = express();
// 모든 출처 허용 (개발용)
app.use(cors());
// 또는 특정 출처만 허용 (프로덕션 권장)
app.use(cors({
origin: 'https://lazybug.io',
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Python + Flask
Python의 Flask 프레임워크에서는 flask-cors
확장을 사용합니다:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# 모든 라우트에 CORS 적용
CORS(app)
# 또는 특정 라우트에만 적용
CORS(app, resources={r"/api/*": {"origins": "https://lazybug.io"}})
@app.route('/api/data')
def get_data():
return {"message": "Hello, CORS!"}
if __name__ == '__main__':
app.run(debug=True)
Django
Django에서는 django-cors-headers
패키지를 사용할 수 있습니다:
# settings.py
INSTALLED_APPS = [
# ...
'corsheaders',
# ...
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
# 다른 미들웨어보다 가능한 앞에 위치시키세요
# ...
]
# 개발 환경 (모든 출처 허용)
CORS_ALLOW_ALL_ORIGINS = True
# 프로덕션 환경 (특정 출처만 허용)
CORS_ALLOWED_ORIGINS = [
"https://lazybug.io",
"https://api.lazybug.io",
]
Apache 서버
Apache에서는 .htaccess
파일을 사용하여 CORS를 설정할 수 있습니다:
Header set Access-Control-Allow-Origin "https://lazybug.io"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
# OPTIONS 요청 처리
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
Nginx 서버
Nginx에서는 설정 파일에 다음과 같이 추가합니다:
server {
location / {
add_header 'Access-Control-Allow-Origin' 'https://lazybug.io';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://lazybug.io';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
}
🔍 CORS 문제 해결을 위한 디버깅 전략
CORS 오류가 발생했을 때, 다음 단계로 문제를 해결해보세요:
1. 오류 메시지 정확히 파악하기
브라우저의 개발자 도구 콘솔에 표시되는 오류 메시지를 자세히 읽어보세요. 대부분의 경우 문제의 원인이 명확히 표시됩니다.

CORS 오류 메시지는 일반적으로 다음과 같은 형태입니다:
Access to fetch at 'https://api.example.com/data' from origin 'https://lazybug.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
이 메시지에서 중요한 정보는:
- 요청하는 출처 (
https://lazybug.io
) - 요청 대상 URL (
https://api.example.com/data
) - 구체적인 CORS 오류 원인 (
No 'Access-Control-Allow-Origin' header is present
)
2. 네트워크 탭에서 요청/응답 헤더 확인
개발자 도구의 네트워크 탭에서 요청을 선택하고 헤더 탭을 확인합니다. 프리플라이트(OPTIONS) 요청과 응답에 적절한 CORS 헤더가 있는지 확인하세요.
특히 다음 헤더를 확인하세요:
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
(자격 증명을 사용하는 경우)
3. 서버 측 로그 확인
서버 로그를 확인하여 CORS 관련 헤더가 올바르게 설정되고 있는지 확인합니다. 로그에서 OPTIONS 요청이 어떻게 처리되고 있는지 살펴보세요.
4. 일반적인 CORS 문제 해결 방법
- Origin 불일치: 요청 출처와
Access-Control-Allow-Origin
헤더 값이 정확히 일치하는지 확인 - 헤더 누락: 필요한 모든 헤더가
Access-Control-Allow-Headers
에 포함되었는지 확인 - 메서드 누락: 사용 중인 HTTP 메서드가
Access-Control-Allow-Methods
에 포함되었는지 확인 - 자격 증명 문제:
credentials: 'include'
를 사용하는 경우 서버에서Access-Control-Allow-Credentials: true
로 설정되었는지 확인 (이 경우Access-Control-Allow-Origin: *
는 사용할 수 없음)
🧪 로컬 개발 환경에서 CORS 우회하기
개발 중에 CORS 문제를 임시로 우회하는 방법도 있습니다:
1. 프록시 서버 사용
Create React App, Vue CLI, Angular CLI 등 대부분의 프론트엔드 개발 환경에서는 개발 서버 프록시 설정을 제공합니다.
React (package.json):
{
"proxy": "http://localhost:5000"
}
Vue (vue.config.js):
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
}
}
Angular (proxy.conf.json):
{
"/api": {
"target": "http://localhost:5000",
"secure": false,
"changeOrigin": true
}
}
2. 브라우저 확장 프로그램
Chrome에서 “CORS Unblock”과 같은 확장 프로그램을 사용하면 개발 중에 CORS 제한을 우회할 수 있습니다. ⚠️ 하지만 이는 개발 용도로만 사용해야 합니다!
3. 브라우저 보안 비활성화 (매우 위험)
Chrome을 다음과 같이 실행할 수 있습니다:
chrome --disable-web-security --user-data-dir="[임시 디렉토리]"
⚠️ 경고: 이 방법은 보안에 매우 취약하므로 격리된 개발 환경에서만 사용하세요!
🛡️ CORS와 보안: 올바른 구현의 중요성
CORS를 올바르게 구현하는 것은 웹 애플리케이션 보안에 매우 중요합니다. 몇 가지 핵심 보안 고려사항을 살펴봅시다:
와일드카드(*) 사용 제한
Access-Control-Allow-Origin: *
는 편리하지만, 모든 도메인의 요청을 허용하므로 프로덕션 환경에서는 피해야 합니다. 대신 신뢰할 수 있는 도메인만 명시적으로 허용하세요.
민감한 API에 자격 증명 요구
민감한 데이터를 다루는 API의 경우, CORS에서 인증된 요청만 허용하도록 설정하세요:
// 클라이언트
fetch('https://api.example.com/sensitive-data', {
credentials: 'include' // 쿠키 포함
});
// 서버
app.use(cors({
origin: 'https://lazybug.io',
credentials: true
}));
동적 Origin 처리
여러 환경(개발, 테스트, 프로덕션)을 지원해야 하는 경우 동적으로 Origin을 확인할 수 있습니다:
app.use(cors({
origin: function(origin, callback) {
const allowedOrigins = [
'https://lazybug.io',
'https://dev.lazybug.io',
'http://localhost:3000'
];
// 허용된 출처에 포함되거나, 서버-서버 요청(origin이 null)인 경우 허용
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('CORS policy violation'));
}
}
}));
📝 CORS 정책 구현의 모범 사례
CORS를 효과적으로 구현하기 위한 모범 사례를 정리해보겠습니다:
- 최소 권한 원칙 적용: 필요한 출처, 헤더, 메서드만 허용하세요
- 와일드카드 사용 자제: 특히 프로덕션 환경에서는 구체적인 출처를 지정하세요
- 인증이 필요한 API에 자격 증명 요구: 보안이 중요한 API에는 인증을 요구하세요
- 프리플라이트 캐싱 활용:
Access-Control-Max-Age
헤더를 사용하여 불필요한 프리플라이트 요청을 줄이세요 - 환경별 설정 분리: 개발, 테스트, 프로덕션 환경에 맞는 CORS 설정을 유지하세요
- 정기적인 테스트: 새로운 API 엔드포인트를 추가할 때마다 CORS 설정이 올바른지 확인하세요
CORS의 이해, 웹 개발의 필수 요소
지금까지 1부에서의 기본 개념과 함께 2부에서는 CORS의 실제 구현 방법, 디버깅 전략, 그리고 모범 사례까지 살펴보았습니다. CORS는 처음에는 귀찮은 장애물처럼 느껴질 수 있지만, 웹의 보안을 위한 중요한 메커니즘임을 이해하셨을 겁니다.
요약하자면:
- CORS는 브라우저의 동일 출처 정책을 안전하게 우회할 수 있는 표준 메커니즘입니다
- 서버 측 설정을 통해 특정 출처의 요청을 허용하거나 거부할 수 있습니다
- 적절한 HTTP 헤더 설정이 CORS 구현의 핵심입니다
- 보안을 위해 필요한 출처만 명시적으로 허용하는 것이 좋습니다
- 디버깅은 오류 메시지와 네트워크 요청을 분석하는 것부터 시작해야 합니다
이제 여러분은 CORS 오류를 마주했을 때 당황하지 않고 체계적으로 문제를 해결할 수 있을 것입니다. 무엇보다 CORS가 웹 보안에 기여하는 중요한 역할을 이해하게 되었습니다.
웹 개발 여정에서 CORS 관련 문제를 만난다면, 이 글을 참고하여 해결해보세요. 그리고 기억하세요 – CORS는 적이 아니라 😅 여러분의 애플리케이션과 사용자를 보호하는 동맹입니다! 🛡️
“CORS가 뭐길래? 웹 개발자가 반드시 알아야 할 교차 출처 리소스 공유 (2부)”에 대한 1개의 생각