본문 바로가기
카테고리 없음

CORS와 SOP 완전정리: React·Next·Spring 연동 가이드

by ctrl-f 2025. 5. 4.

CORS(Cross-Origin Resource Sharing)

 

CORS(Cross-Origin Resource Sharing)는 브라우저에서 발생하는 보안 정책인 SOP(Same-Origin Policy, 동일 출처 정책)를 우회하기 위한 메커니즘입니다. 프론트엔드와 백엔드를 분리해 개발하는 환경, 특히 React, Next.jsSpring Boot를 함께 사용하는 구조에서는 CORS 문제가 매우 흔하게 발생합니다. 본 글에서는 SOP와 CORS의 개념, CORS 요청 흐름, 그리고 실무에서 발생하는 에러 사례 및 해결 전략을 구조적으로 정리합니다.

SOP(Same-Origin Policy)와 CORS란 무엇인가?

SOP(Same-Origin Policy)는 웹 브라우저의 보안 정책으로, 출처(origin)가 다른 리소스에 대한 접근을 제한합니다. 출처는 프로토콜, 호스트, 포트를 기준으로 판단되며, 이 세 가지 중 하나라도 다르면 다른 출처로 간주됩니다.

예:

  • http://localhost:3000 (React 앱)
  • http://localhost:8080 (Spring Boot API)

위 두 주소는 포트가 다르므로 다른 출처입니다. 이 경우, React 앱에서 API를 호출하려고 하면 브라우저는 SOP에 의해 접근을 차단합니다.

이를 해결하기 위해 등장한 것이 CORS입니다. CORS는 서버가 브라우저에게 “이 출처에서의 요청을 허용한다”고 명시적으로 알려주는 방식으로 동작합니다.

1. CORS 요청 흐름

브라우저에서 cross-origin 요청을 보낼 때, 요청 방식(method)이나 헤더에 따라 단순 요청(simple request) 또는 사전 요청(preflight request)으로 나뉩니다.

  • 단순 요청: GET, POST(특정 조건), HEAD로 보내는 단순한 요청
  • 프리플라이트 요청: OPTIONS 요청을 먼저 보내 서버의 허용 여부를 확인

서버가 CORS를 허용하면 응답 헤더에 다음과 같은 정보가 포함됩니다:

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type

이 설정이 없다면 브라우저는 실제 요청을 차단하고 CORS 오류를 발생시킵니다.

React / Next.js + Spring Boot에서 발생하는 CORS 문제

프론트엔드와 백엔드를 분리 개발하는 환경에서 CORS 오류는 대부분 다음 상황에서 발생합니다:

1. 개발 중 포트가 다를 경우

  • React 개발 서버: localhost:3000
  • Spring Boot 백엔드: localhost:8080

React 앱에서 API를 호출하면 다른 origin이므로 브라우저는 CORS 정책에 따라 요청을 차단합니다.

2. 브라우저 콘솔 에러 메시지 예시

Access to fetch at 'http://localhost:8080/api/data'
from origin 'http://localhost:3000'
has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present.

3. Next.js 프록시 설정 방식

Next.js에서는 개발 중 CORS 우회를 위해 next.config.js에서 rewrite 또는 proxy 설정을 사용합니다.

// next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'http://localhost:8080/api/:path*', // Spring Boot API
      },
    ];
  },
};

이 설정을 통해 브라우저 입장에서는 동일 origin에서 요청하는 것처럼 보이므로 CORS 오류가 발생하지 않습니다.

4. Spring Boot에서 CORS 허용 방법

전역 설정 방식 (Spring WebMvcConfigurer)

@Configuration
public class WebConfig implements WebMvcConfigurer {
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
            .allowedOrigins("http://localhost:3000")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*")
            .allowCredentials(true);
  }
}

컨트롤러 개별 설정도 가능하지만, 유지보수나 확장성 측면에서는 전역 설정이 권장됩니다.

CORS 실무 해결 전략과 면접 대응법

1. 실무 적용 전략 요약

  • 개발 환경: 프론트엔드 프록시 설정 또는 Spring의 @CrossOrigin 사용
  • 운영 환경: nginx 또는 gateway 레벨에서 CORS 처리 권장
  • 서버 응답 헤더: 반드시 Access-Control-Allow-Origin 포함

2. Next.js 미들웨어로 제어하는 방법

// middleware.ts (Next.js 13+)
import { NextResponse } from 'next/server';

export function middleware(req) {
  const res = NextResponse.next();
  res.headers.set('Access-Control-Allow-Origin', '*');
  return res;
}

Next.js 13 이후의 미들웨어 기능을 활용하면 CORS 헤더를 직접 제어할 수 있습니다. 단, 이 방식은 브라우저 단에서의 오류는 해결 못하므로 프록시 또는 백엔드 설정이 우선입니다.

3. 면접 질문 예시

  • “CORS란 무엇이며 왜 필요할까요?”
  • “SOP와 CORS의 차이를 설명해주세요.”
  • “React에서 Spring Boot API 호출 시 CORS 오류가 발생했을 때 어떻게 해결하셨나요?”
  • “프리플라이트 요청이란 무엇인가요?”

4. 면접 답변 팁

“SOP는 브라우저의 보안 정책으로 동일 출처가 아닐 경우 요청을 제한합니다. 이를 해결하기 위해 CORS가 사용되며, 서버가 허용된 origin에 대해 응답 헤더를 통해 허용 여부를 명시합니다. 실무에서는 Spring Boot의 WebMvcConfigurer를 활용해 허용 도메인을 설정하거나, 개발 중에는 프론트엔드 프록시 설정을 통해 CORS 문제를 우회한 경험이 있습니다.”

결론

CORS는 브라우저 보안 정책인 SOP를 우회하여 프론트엔드와 백엔드가 분리된 구조에서도 원활한 통신을 가능하게 해주는 핵심 기술입니다. React, Next.js, Spring Boot 같은 프레임워크를 함께 사용하는 현대 개발 환경에서, CORS 설정은 단순한 에러 해결을 넘어 구조적 이해가 필요한 영역입니다.

실무에서는 개발과 운영 환경 모두에서의 CORS 설정이 요구되며, 면접에서는 단순 정의보다 요청 흐름, preflight 동작, 프록시 활용 경험을 포함한 설명이 효과적입니다. 개발자라면 최소한 CORS 오류를 정확히 읽고, 구조적으로 해결할 수 있는 역량이 필요합니다.