웹 개발에서 CORS(Cross-Origin Resource Sharing)는 매우 중요한 개념입니다. 특히 API 서버를 개발하거나 클라이언트와 서버가 다른 도메인에 있는 경우, CORS는 클라이언트와 서버 간의 통신을 제어하고 보안을 강화하는 역할을 합니다. 이 글에서는 CORS의 정의, 동작 방식, 설정 방법, 그리고 주의사항을 자세히 다룹니다.
1. CORS란?
CORS(Cross-Origin Resource Sharing)는 브라우저가 한 출처(Origin)에서 실행 중인 웹 애플리케이션이 다른 출처의 리소스에 접근할 수 있도록 허용하거나 차단하는 보안 메커니즘입니다.
출처(Origin)란?
출처는 다음 세 요소를 조합하여 정의됩니다:
- 프로토콜: HTTP, HTTPS 등
- 호스트: 도메인 이름 또는 IP 주소
- 포트 번호
출처가 다르면, 브라우저는 기본적으로 해당 요청을 차단합니다. 이를 Same-Origin Policy(동일 출처 정책)이라고 하며, CORS는 이를 우회하는 안전한 방법을 제공합니다.
동일 출처 예시
- https://example.com → https://example.com (동일 출처)
- https://example.com:3000 → https://example.com (다른 출처)
2. CORS가 필요한 이유
2.1 동일 출처 정책의 한계
동일 출처 정책은 보안을 위해 클라이언트가 다른 출처의 리소스에 접근하지 못하도록 제한합니다. 그러나 현대 웹 애플리케이션에서는 다음과 같은 이유로 다른 출처의 리소스에 접근해야 할 경우가 많습니다.
- RESTful API 호출
- 클라우드에서 호스팅된 리소스 로드
- 제3자 서비스와 통신 (예: 결제 게이트웨이)
2.2 CORS의 역할
CORS는 브라우저와 서버 간의 협의를 통해 이러한 제한을 안전하게 우회합니다. 서버는 허용된 출처와 허용된 요청 방식을 명시적으로 선언하여 클라이언트가 리소스에 접근할 수 있도록 허용합니다.
3. CORS 동작 방식
CORS 요청은 크게 두 가지로 나뉩니다.
- Simple Request(단순 요청)
- Preflight Request(사전 요청)
3.1 Simple Request
단순 요청은 다음 조건을 모두 만족하는 요청입니다.
- HTTP 메서드: GET, POST, 또는 HEAD
- 요청 헤더: Accept, Content-Type, 또는 Authorization만 포함
- 요청 본문: 텍스트 또는 기본 데이터 형식
단순 요청에서는 서버가 응답 헤더에 허용된 출처를 명시합니다.
Simple Request 예제
클라이언트 요청
fetch('https://api.example.com/data', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
서버 응답
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Content-Type: application/json
3.2 Preflight Request
단순 요청 조건을 만족하지 못하는 경우, 브라우저는 실제 요청을 보내기 전에 OPTIONS 메서드를 사용하여 서버의 허용 여부를 확인합니다. 이를 Preflight Request라고 합니다.
Preflight Request 흐름
- 브라우저가 OPTIONS 요청을 보냅니다.
- 서버가 허용된 출처, 메서드, 헤더를 응답으로 반환합니다.
- 브라우저가 서버 응답을 확인한 후 실제 요청을 보냅니다.
Preflight Request 예제
Preflight OPTIONS 요청
OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: https://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
서버 응답
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
4. 서버에서 CORS 설정하기
4.1 Express.js에서 설정
Express를 사용하는 Node.js 서버에서 CORS를 설정하려면 cors 패키지를 사용하는 것이 가장 간단합니다.
설치
npm install cors
설정
const express = require('express');
const cors = require('cors');
const app = express();
// 모든 출처 허용
app.use(cors());
// 특정 출처만 허용
app.use(cors({
origin: 'https://example.com',
}));
app.get('/data', (req, res) => {
res.json({ message: 'CORS 설정 완료!' });
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
4.2 다른 서버에서의 설정
4.2.1 Nginx
Nginx를 사용 중이라면 다음 설정을 추가합니다.
server {
location /api/ {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
if ($request_method = 'OPTIONS') {
return 204;
}
}
}
4.2.2 Flask
Python Flask에서 CORS 설정은 flask-cors 라이브러리를 사용하여 처리합니다.
pip install flask-cors
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route('/data')
def data():
return {'message': 'CORS 설정 완료!'}
if __name__ == '__main__':
app.run()
5. CORS 관련 오류와 해결 방법
5.1 브라우저에서 발생하는 CORS 오류
오류 메시지
Access to fetch at 'https://api.example.com/data' from origin 'https://another.com' has been blocked by CORS policy.
해결 방법
- 서버에서 Access-Control-Allow-Origin 헤더를 적절히 설정하세요.
- Preflight 요청이 실패하는 경우, OPTIONS 메서드 처리가 서버에 추가되어야 합니다.
6. CORS 보안 관련 팁
- 출처 제한: Access-Control-Allow-Origin에 와일드카드(*)를 사용하지 말고, 신뢰할 수 있는 출처만 명시하세요.
- 자격 증명: credentials가 포함된 요청(withCredentials: true)의 경우, 반드시 Access-Control-Allow-Origin에 와일드카드를 사용할 수 없습니다.
- OPTIONS 처리: 서버는 반드시 Preflight 요청을 허용하도록 구성되어야 합니다.
CORS는 클라이언트와 서버 간의 안전한 데이터 교환을 가능하게 하는 중요한 메커니즘입니다. 이를 이해하고 적절히 설정하면 보안과 사용자 경험을 모두 강화할 수 있습니다. Express, Flask, Nginx와 같은 다양한 환경에서 CORS를 설정하고, 발생 가능한 오류를 해결하는 방법을 알아두세요. 이제 여러분의 프로젝트에서 CORS 문제를 자신 있게 해결할 수 있을 것입니다! 🚀
'Programming > server' 카테고리의 다른 글
| MongoDB: NoSQL 데이터베이스의 강력한 선택지 (0) | 2024.12.07 |
|---|---|
| SQLite: 경량화된 관계형 데이터베이스의 모든 것 (1) | 2024.12.07 |
| Express.js: Node.js 웹 애플리케이션 개발의 필수 도구 (0) | 2024.12.07 |