CORS, 도대체 왜 막는 건데?

Suyo·2025년 7월 29일
0
post-thumbnail

– 프론트엔드 개발자의 입장에서 이해하는 CORS 이슈와 해결법

웹 개발을 하다 보면, 다음과 같은 에러를 종종 마주친다.
프론트에선 API 호출도 했고, 백엔드에서도 응답을 보내줬는데…

“아니, 응답은 있는데 왜 못 쓰게 하는 건데?”
처음엔 너무 억울하다. 그래서 이번 글에서는 프론트엔드 입장에서 CORS가 왜 발생하는지, 어떻게 해결해야 하는지를 정리한다.


1. CORS란?

CORS (Cross-Origin Resource Sharing):
브라우저가 출처(origin)가 다른 리소스에 접근할 때 허용 여부를 판단하는 보안 정책이다.

  • 1.1 출처(origin)이란
    프로토콜 + 도메인 + 포트 번호 세 가지를 조합한 것이다.
    예를 들어:

    • http://localhost:3000 → 프론트 서버
    • http://localhost:8080 → 백엔드 서버
      는 서로 다른 출처다.

2. 브라우저가 CORS를 강제하는 이유

  • 2.1 보안상의 이유
    악성 스크립트가 다른 도메인의 API에 함부로 요청을 보내는 것을 막기 위해
    브라우저가 먼저 요청을 '차단'하는 구조다.

  • 2.2 브라우저만 강제
    Postman이나 curl 같은 툴에선 아무런 문제가 없다.


3. 프론트엔드 개발할 때 겪는 흔한 상황

3.1 상황 예시

// React에서 fetch로 API 호출
fetch("http://localhost:8080/api/data")
  .then((res) => res.json())
  .then((data) => console.log(data));

3.2 결과

백엔드에서 응답도 잘 오는데... 에러가 발생한다!

Access to fetch at 'http://localhost:8080/api/data' from origin 'http://localhost:3000' has been blocked by CORS policy

4. 어떻게 해결할 수 있을까?

4.1 백엔드에서 CORS 허용 설정하기 (정석)

백엔드가 클라이언트의 출처를 허용한다고 명시해줘야 한다.

4.1.1 Spring Boot 예시

@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/api/data")
public Data getData() {
    return new Data();
}

4.1.2 Node.js (Express) 예시

app.use(
  cors({
    origin: "http://localhost:3000",
  })
);

4.2 프론트에서 프록시 설정하기 (개발 환경에서 자주 사용)

CRA (React Create App)에서는 package.json에 프록시 설정 가능

"proxy": "http://localhost:8080"
  • 4.2.1 프론트 서버가 먼저 받고 백엔드로 전달하기 때문에
    CORS를 우회할 수 있다.

  • 4.2.2 주의: 이 방식은 개발 환경 전용이다.
    배포 시엔 사용할 수 없다.


5. Preflight 요청이란?

  • 5.1 Content-Type: application/json 같이 민감한 헤더가 포함되면
    브라우저는 본 요청 전에 **OPTIONS 메서드로 사전 검사 요청(Preflight)**을 보낸다.
OPTIONS /api/data HTTP/1.1
Origin: http://localhost:3000
Access-Control-Request-Method: POST
  • 5.2 백엔드는 이 요청에 제대로 응답해줘야 한다.
    안 해주면 역시나 CORS 에러 발생!

6. 마무리하며

CORS는 막는 게 목적이 아니라, 허용을 명시하라는 시스템이다.
프론트 입장에서는 “막혀서 짜증나”지만, 브라우저가 사용자를 지켜주는 장치라는 걸 이해하고,
백엔드와 협의해서 CORS 설정을 조율해나가는 게 현실적인 접근이다.

profile
Mee-

0개의 댓글