CORS 에러 완벽 가이드: 원인 분석부터 해결, 예방까지 (IT 관리자 필독)
웹 개발 및 IT 인프라 운영 시 CORS (Cross-Origin Resource Sharing) 에러는 흔히 발생하는 문제 중 하나입니다. 특히 서로 다른 도메인 간에 API 요청을 처리할 때 자주 발생하며, 보안상의 이유로 브라우저에서 Same-Origin Policy (SOP, 동일 출처 정책)를 적용하기 때문에 발생합니다. 이 글에서는 CORS 에러의 원인을 심층적으로 분석하고, 단계별 해결 방법과 예방 조치까지 상세하게 안내하여 IT 관리자 및 엔지니어들이 실무에서 겪는 어려움을 해소하고자 합니다.
목차
에러 현상
다음과 같은 에러 메시지를 브라우저 콘솔에서 확인할 수 있습니다.
Access to XMLHttpRequest at 'https://api.contoso.com/data' from origin 'https://www.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
또는
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.contoso.com/data. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
이 에러는 https://www.example.com 에서 https://api.contoso.com/data 로의 요청이 CORS 정책에 의해 차단되었음을 의미합니다. 이는 API 서버 (api.contoso.com)가 https://www.example.com 으로부터의 요청을 허용하도록 설정되지 않았기 때문에 발생합니다.
발생 환경:
- 브라우저: Chrome, Firefox, Safari 등 모든 최신 브라우저
- 서버: Node.js, Apache, Nginx, IIS 등 다양한 웹 서버 환경
- 상황: 프론트엔드 애플리케이션이 백엔드 API 서버에 Ajax 요청을 보낼 때, 특히 서로 다른 도메인 또는 포트를 사용하는 경우
원인 분석
CORS 에러의 주요 원인은 다음과 같습니다.
1. 서버의 Access-Control-Allow-Origin 헤더 미설정 (빈도: 높음)
서버가 응답 헤더에 Access-Control-Allow-Origin 헤더를 포함하지 않거나, 요청을 보낸 출처 (Origin)를 허용하지 않는 경우 CORS 에러가 발생합니다. 브라우저는 이 헤더를 확인하여 요청을 보낸 출처가 서버에서 허용되었는지 판단합니다. HTTP 헤더 설정이 누락되었거나 잘못 설정된 것이 주된 원인입니다.
2. Preflight Request 실패 (빈도: 중간)
OPTIONS 메소드를 사용하는 Preflight Request는 브라우저가 실제 요청을 보내기 전에 서버에게 CORS 정책 준수 여부를 확인하는 과정입니다. 이 Preflight Request가 실패하는 경우 (예: 서버가 OPTIONS 요청에 대한 적절한 응답을 반환하지 않는 경우) CORS 에러가 발생합니다. 서버 설정 오류 또는 프록시 서버 설정 문제가 원인일 수 있습니다.
3. 잘못된 Origin 헤더 (빈도: 낮음)
클라이언트에서 보내는 Origin 헤더가 올바르지 않은 경우에도 CORS 에러가 발생할 수 있습니다. 예를 들어, Origin 헤더에 프로토콜 (http/https) 또는 포트 번호가 누락된 경우 서버가 출처를 제대로 인식하지 못하여 에러가 발생할 수 있습니다.
해결 방법
1. Access-Control-Allow-Origin 헤더 설정
서버에서 Access-Control-Allow-Origin 헤더를 설정하여 요청을 보낸 출처를 허용해야 합니다. 서버 설정 방법에 따라 설정 방법이 다릅니다.
Node.js (Express)
const express = require('express');
const cors = require('cors');
const app = express();
// 모든 출처 허용 (개발 환경에서만 사용)
// app.use(cors());
// 특정 출처 허용
const corsOptions = {
origin: 'https://www.example.com'
};
app.use(cors(corsOptions));
app.get('/data', (req, res) => {
res.json({ message: 'Hello from API!' });
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
실행 전 확인: 브라우저 개발자 도구에서 Network 탭을 열어 CORS 에러가 발생하는 API 요청을 확인합니다.
실행 후 확인: 서버를 재시작하고, 동일한 API 요청을 다시 보내 Access-Control-Allow-Origin 헤더가 응답에 포함되었는지 확인합니다. 에러가 사라졌는지 확인합니다.
Apache
.htaccess 파일에 다음 설정을 추가합니다.
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://www.example.com"
</IfModule>
또는, 모든 출처를 허용하려면 다음과 같이 설정합니다 (보안에 유의).
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
실행 전 확인: Apache 서버 설정 파일 또는 .htaccess 파일에 기존 CORS 관련 설정이 없는지 확인합니다.
실행 후 확인: Apache 서버를 재시작하고, API 요청을 다시 보내 Access-Control-Allow-Origin 헤더가 응답에 포함되었는지 확인합니다. 에러가 사라졌는지 확인합니다.
Nginx
Nginx 설정 파일 (nginx.conf)에 다음 설정을 추가합니다.
http {
server {
location / {
add_header Access-Control-Allow-Origin "https://www.example.com";
}
}
}
또는, 모든 출처를 허용하려면 다음과 같이 설정합니다 (보안에 유의).
http {
server {
location / {
add_header Access-Control-Allow-Origin "*";
}
}
}
실행 전 확인: Nginx 설정 파일에서 기존 CORS 관련 설정이 없는지 확인합니다.
실행 후 확인: Nginx 서버를 재시작하고, API 요청을 다시 보내 Access-Control-Allow-Origin 헤더가 응답에 포함되었는지 확인합니다. 에러가 사라졌는지 확인합니다.
2. Preflight Request 처리
Preflight Request (OPTIONS 요청)에 대한 적절한 응답을 반환하도록 서버를 설정해야 합니다. 특히 Access-Control-Allow-Methods 및 Access-Control-Allow-Headers 헤더를 설정해야 합니다.
Node.js (Express)
app.options('/data', (req, res) => {
res.header('Access-Control-Allow-Origin', 'https://www.example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.sendStatus(204);
});
실행 전 확인: 브라우저 개발자 도구에서 Network 탭을 열어 Preflight Request (OPTIONS) 요청이 실패하는지 확인합니다.
실행 후 확인: 서버를 재시작하고, 동일한 API 요청을 다시 보내 Preflight Request가 성공적으로 처리되는지 확인합니다. Access-Control-Allow-Methods 및 Access-Control-Allow-Headers 헤더가 응답에 포함되었는지 확인합니다.
Apache/Nginx
Apache 또는 Nginx 설정에서 OPTIONS 요청에 대한 처리를 추가합니다. 예를 들어, Nginx에서는 다음과 같이 설정할 수 있습니다.
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin "https://www.example.com";
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
return 204;
}
실행 전 확인: Apache 또는 Nginx 설정 파일에서 기존 OPTIONS 요청 처리 설정이 없는지 확인합니다.
실행 후 확인: 서버를 재시작하고, API 요청을 다시 보내 Preflight Request가 성공적으로 처리되는지 확인합니다. Access-Control-Allow-Methods 및 Access-Control-Allow-Headers 헤더가 응답에 포함되었는지 확인합니다.
3. Origin 헤더 확인 및 수정
클라이언트에서 보내는 Origin 헤더가 올바른지 확인하고, 필요한 경우 수정합니다. JavaScript 코드에서 Origin 헤더를 직접 설정하는 것은 불가능하지만, 프록시 서버를 사용하여 Origin 헤더를 변경할 수 있습니다.
예방 조치
1. CORS 설정 자동화 스크립트
서버 환경에 맞는 CORS 설정을 자동으로 구성하는 스크립트를 작성하여 배포 프로세스에 통합합니다. 예를 들어, Node.js 환경에서는 다음과 같은 스크립트를 사용할 수 있습니다.
#!/bin/bash
# .env 파일에서 CORS_ORIGIN 변수 읽기
ORIGIN=$(grep CORS_ORIGIN .env | cut -d '=' -f 2)
# Nginx 설정 파일 수정
sed -i "s/add_header Access-Control-Allow-Origin ".*";/add_header Access-Control-Allow-Origin \"$ORIGIN\";/g" /etc/nginx/nginx.conf
# Nginx 재시작
systemctl restart nginx
echo "CORS 설정이 업데이트되었습니다. 허용된 Origin: $ORIGIN"
2. 모니터링 및 알림 설정
CORS 에러 발생 여부를 주기적으로 모니터링하고, 에러가 발생하면 즉시 알림을 받을 수 있도록 시스템을 구축합니다. ELK 스택 또는 Prometheus와 Grafana를 사용하여 CORS 관련 로그를 분석하고 시각화할 수 있습니다.
3. CORS 설정 가이드라인 문서화
팀 내에서 CORS 설정을 일관성 있게 유지하기 위해 CORS 설정 가이드라인을 문서화하고, 새로운 프로젝트를 시작할 때 이를 준수하도록 합니다. 가이드라인에는 허용 가능한 Origin 목록, Preflight Request 처리 방법, 보안 고려 사항 등이 포함되어야 합니다.
FAQ
Q: CORS 에러는 왜 발생하는 건가요?
A: CORS 에러는 브라우저의 보안 정책(Same-Origin Policy) 때문에 발생합니다. 서로 다른 Origin (프로토콜, 호스트, 포트) 간의 리소스 접근을 제한하여 보안을 강화하는 것이 목적입니다. 서버에서 적절한 CORS 설정을 하지 않으면 다른 Origin에서 리소스에 접근할 때 에러가 발생합니다.
Q: Access-Control-Allow-Origin 헤더는 무엇인가요?
A: Access-Control-Allow-Origin은 서버가 클라이언트에게 허용된 Origin을 알려주는 HTTP 헤더입니다. 이 헤더에 특정 Origin을 명시하거나 ''를 사용하여 모든 Origin을 허용할 수 있습니다. 하지만 보안상의 이유로 '' 사용은 신중해야 합니다. 특정 Origin만 허용하는 것이 좋습니다.
Q: CORS 에러를 해결하기 위해 브라우저 설정을 변경하는 것이 안전한가요?
A: CORS 에러를 해결하기 위해 브라우저 설정을 변경하는 것은 권장하지 않습니다. 이는 보안에 취약해질 수 있으며, 프로덕션 환경에서는 사용할 수 없는 방법입니다. 서버 측에서 CORS 설정을 올바르게 구성하는 것이 가장 안전하고 올바른 해결 방법입니다.
'B2B Solution' 카테고리의 다른 글
| Docker vs Podman 비교 분석: 컨테이너 런타임 선택 가이드 (0) | 2026.03.07 |
|---|---|
| EKS vs GKE vs AKS: 관리형 쿠버네티스 서비스 심층 비교 분석 (0) | 2026.03.06 |
| Kubernetes Pod OOMKilled 에러 해결 가이드: 원인 분석 및 단계별 해결 (0) | 2026.03.05 |
| GitHub Actions vs GitLab CI: CI/CD 플랫폼 심층 비교 분석 및 선택 가이드 (0) | 2026.03.05 |
| Datadog vs New Relic 비교 분석: IT 인프라 모니터링 솔루션 선택 가이드 (0) | 2026.03.05 |