본문 바로가기
개발/웹 개발

Day 5: CORS (Cross-Origin Resource Sharing)

1. 오늘의 학습 목표

학습 목표: 브라우저의 핵심 보안 정책인 '동일 출처 정책(SOP)'을 이해하고, 이 정책을 안전하게 우회하여 다른 출처의 리소스를 요청할 수 있게 해주는 CORS의 동작 원리를 이해합니다.

 

핵심 요약: CORS는 다른 도메인의 서버와 안전하게 통신하기 위해 반드시 알아야 하는 웹 표준입니다. 프론트엔드 개발자라면 누구나 한 번쯤 마주치는 CORS 에러의 원인과 해결책을 배웁니다.


2. 핵심 개념 파헤치기

2.1. 왜 CORS가 필요한가? - 동일 출처 정책

먼저 CORS를 이해하려면 브라우저의 동일 출처 정책(SOP)을 알아야 합니다. 이 정책은 "A 출처(Origin)에서 로드된 문서는 B 출처의 리소스와 상호작용할 수 없다"는 기본적인 보안 규칙입니다. 여기서 출처는 프로토콜, 호스트, 포트(:80) 세 가지가 모두 같아야 동일 출처로 인정됩니다.

이 정책이 없다면, 악의적인 웹사이트가 우리가 로그인해 둔 다른 사이트(은행, 이메일 등)의 정보를 마음대로 가져갈 수 있는 심각한 보안 문제가 발생할 수 있습니다.

 

2.2. CORS (Cross-Origin Resource Sharing)란 무엇인가?

SOP는 중요하지만, 현대 웹에서는 다른 출처의 API를 호출하거나 폰트, 이미지 등을 가져오는 일이 매우 흔합니다. CORS는 이렇게 다른 출처 간의 리소스 공유를 허용하기 위한 표준 메커니즘입니다.

핵심 원리는 간단합니다. 리소스를 요청받는 서버가 응답 헤더에 Access-Control-Allow-Origin과 같은 특정 헤더를 포함하여 "이 출처는 내 리소스를 사용해도 좋아"라고 명시적으로 허락해주는 방식입니다. 이 허락을 받은 브라우저만이 클라이언트에게 응답 데이터를 전달해 줍니다. 즉, CORS 에러의 해결은 서버 측에서 이루어져야 합니다.


3. 코드로 배우기

3.1. 구현 목표

JavaScript fetch를 이용해 다른 포트에서 실행 중인 서버에 API 요청을 보내 일부러 CORS 에러를 발생시킨 후, 서버 측 코드를 수정하여 에러를 해결합니다.

3.2. [1단계: 클라이언트 코드 작성 (HTML)]

http://127.0.0.1:5500에서 실행될 간단한 HTML 파일입니다. 이 파일은 http://localhost:3000에 있는 서버로 데이터를 요청할 것입니다. (포트 번호가 다르므로 다른 출처입니다.)

<!DOCTYPE html>
<html>
<head>
  <title>CORS Test</title>
</head>
<body>
  <h1>CORS 에러 테스트</h1>
  <p>F12 개발자 도구의 콘솔을 확인하세요.</p>

  <script>
    fetch('http://localhost:3000/data')
      .then(response => response.json())
      .then(data => console.log('성공:', data))
      .catch(error => console.error('에러 발생:', error));
  </script>
</body>
</html>

3.3. [2단계: 서버 코드 작성 (Node.js/Express) - CORS 적용 전]

3000번 포트에서 실행되며, /data 경로로 요청이 오면 간단한 JSON을 응답하는 서버입니다. 아직 CORS 관련 설정이 없습니다.

//server.js (node server.js 로 3000번 포트에서 실행)
const express = require('express');
const app = express();
const port = 3000;

app.get('/data', (req, res) => {
  res.json({ message: '이 데이터는 다른 출처에서 왔습니다!' });
});

app.listen(port, () => {
  console.log(`서버가 http://localhost:${port} 에서 실행 중입니다.`);
});

위 상태에서 index.html을 실행하면, 브라우저 콘솔에 CORS 에러가 발생하는 것을 볼 수 있습니다.

 

3.4. [3단계: 서버 코드 수정 - CORS 해결]

서버 응답 헤더에 Access-Control-Allow-Origin을 추가하여 http://127.0.0.1:5500 출처의 요청을 허용해 줍니다.

const express = require('express');
const app = express();
const port = 3000;

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500');
  next();  //다음 미들웨어 또는 라우트 핸들러로 이동
});

app.get('/data', (req, res) => {
  res.json({ message: '이 데이터는 다른 출처에서 왔습니다!' });
});

app.listen(port, () => {
  console.log(`서버가 http://localhost:${port} 에서 실행 중입니다.`);
});

4. 전체 코드

const express = require('express');
const app = express();
const port = 3000;

//CORS 미들웨어: 특정 출처 허용
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

//GET /data 요청 처리
app.get('/data', (req, res) => {
  res.json({ message: '이 데이터는 다른 출처에서 왔습니다!' });
});

//서버 실행
app.listen(port, () => {
  console.log(`서버가 http://localhost:${port} 에서 실행 중입니다.`);
});

'개발 > 웹 개발' 카테고리의 다른 글

Day 7: CSS 선택자와 명시도  (0) 2024.08.02
Day 6: HTML과 시맨틱 웹  (1) 2024.08.02
Day 4: 동기 vs 비동기  (2) 2024.07.31
Day 3: REST API의 이해  (0) 2024.07.29
Day 2: HTTP/HTTPS 프로토콜  (0) 2024.07.28