Programming/server

CORS(Cross-Origin Resource Sharing): 완벽 가이드

Fillim 2024. 12. 7. 11:24

웹 개발에서 CORS(Cross-Origin Resource Sharing)는 매우 중요한 개념입니다. 특히 API 서버를 개발하거나 클라이언트와 서버가 다른 도메인에 있는 경우, CORS는 클라이언트와 서버 간의 통신을 제어하고 보안을 강화하는 역할을 합니다. 이 글에서는 CORS의 정의, 동작 방식, 설정 방법, 그리고 주의사항을 자세히 다룹니다.

 

1. CORS란?

CORS(Cross-Origin Resource Sharing)는 브라우저가 한 출처(Origin)에서 실행 중인 웹 애플리케이션이 다른 출처의 리소스에 접근할 수 있도록 허용하거나 차단하는 보안 메커니즘입니다.

출처(Origin)란?

출처는 다음 세 요소를 조합하여 정의됩니다:

  1. 프로토콜: HTTP, HTTPS 등
  2. 호스트: 도메인 이름 또는 IP 주소
  3. 포트 번호

출처가 다르면, 브라우저는 기본적으로 해당 요청을 차단합니다. 이를 Same-Origin Policy(동일 출처 정책)이라고 하며, CORS는 이를 우회하는 안전한 방법을 제공합니다.

동일 출처 예시

 

2. CORS가 필요한 이유

2.1 동일 출처 정책의 한계

동일 출처 정책은 보안을 위해 클라이언트가 다른 출처의 리소스에 접근하지 못하도록 제한합니다. 그러나 현대 웹 애플리케이션에서는 다음과 같은 이유로 다른 출처의 리소스에 접근해야 할 경우가 많습니다.

  • RESTful API 호출
  • 클라우드에서 호스팅된 리소스 로드
  • 제3자 서비스와 통신 (예: 결제 게이트웨이)

2.2 CORS의 역할

CORS는 브라우저와 서버 간의 협의를 통해 이러한 제한을 안전하게 우회합니다. 서버는 허용된 출처와 허용된 요청 방식을 명시적으로 선언하여 클라이언트가 리소스에 접근할 수 있도록 허용합니다.

 

3. CORS 동작 방식

CORS 요청은 크게 두 가지로 나뉩니다.

  1. Simple Request(단순 요청)
  2. 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 흐름

  1. 브라우저가 OPTIONS 요청을 보냅니다.
  2. 서버가 허용된 출처, 메서드, 헤더를 응답으로 반환합니다.
  3. 브라우저가 서버 응답을 확인한 후 실제 요청을 보냅니다.

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.

 

해결 방법

  1. 서버에서 Access-Control-Allow-Origin 헤더를 적절히 설정하세요.
  2. Preflight 요청이 실패하는 경우, OPTIONS 메서드 처리가 서버에 추가되어야 합니다.

 

6. CORS 보안 관련 팁

  1. 출처 제한: Access-Control-Allow-Origin에 와일드카드(*)를 사용하지 말고, 신뢰할 수 있는 출처만 명시하세요.
  2. 자격 증명: credentials가 포함된 요청(withCredentials: true)의 경우, 반드시 Access-Control-Allow-Origin에 와일드카드를 사용할 수 없습니다.
  3. OPTIONS 처리: 서버는 반드시 Preflight 요청을 허용하도록 구성되어야 합니다.

 

CORS는 클라이언트와 서버 간의 안전한 데이터 교환을 가능하게 하는 중요한 메커니즘입니다. 이를 이해하고 적절히 설정하면 보안과 사용자 경험을 모두 강화할 수 있습니다. Express, Flask, Nginx와 같은 다양한 환경에서 CORS를 설정하고, 발생 가능한 오류를 해결하는 방법을 알아두세요. 이제 여러분의 프로젝트에서 CORS 문제를 자신 있게 해결할 수 있을 것입니다! 🚀