본문 바로가기
프론트엔드

CORS와 SOP의 개념 및 구현 방법 이해하기

by parkjongdi 2025. 5. 12.
728x90
반응형

C0RS란?

  • Cross-Origin Resource Sharing의 약자
  • 다른 출처(도메인, 포트, 프로토콜)의 리소스에 접근할 수 있게 하는 HTTP 헤더 기반 메커니즘
  • 웹 애플리케이션이 자신의 출처가 아닌 다른 출처에서 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제

필요성

  • 현대 웹 애플리케이션은 여러 도메인의 리소스를 필요로 함
  • REST API와 프론트엔드가 서로 다른 도메인에서 실행되는 경우가 많음
  • 서드파티 API 활용 시 필수적
  • SOP의 제한을 안전하게 완화하기 위해 필요

SOP란?

  • Same-Origin Policy(동일 출처 정책)의 약자
  • 웹 브라우저가 실행 중인 웹 페이지와 동일한 출처의 리소스만 접근할 수 있도록 제한하는 보안 정책
  • 동일 출처 = 같은 프로토콜 + 같은 호스트 + 같은 포트

한계

  • 현대 웹 환경에서는 다양한 출처의 리소스 사용이 필요함
  • 마이크로서비스 아키텍처에서는 여러 도메인 간 통신이 필수적
  • CDN이나 클라우드 서비스 사용 시 제약이 생김
  • 이러한 제약을 안전하게 우회하기 위해 CORS가 도입됨

CORS 작동 방식

단순 요청 (Simple Request)

  1. 브라우저가 다른 출처로 HTTP 요청 전송
  2. 요청에 Origin 헤더 포함 (요청 출처 명시)
  3. 서버는 Access-Control-Allow-Origin 헤더로 응답
  4. 브라우저가 응답 헤더를 확인하여 접근 허용 여부 결정

예비 요청 (Preflight Request)

  1. 본 요청 전에 OPTIONS 메서드로 예비 요청 전송
  2. 예비 요청에 실제 요청의 메서드, 헤더 정보 포함
  3. 서버가 허용 여부를 CORS 헤더로 응답
  4. 허용된 경우에만 본 요청 전송

인증 정보 포함 요청

  • withCredentials: true 설정 시 쿠키와 같은 인증 정보 포함
  • 서버는 Access-Control-Allow-Credentials: true로 응답
  • 이 경우 Access-Control-Allow-Origin에 와일드카드(*) 사용 불가

CORS 헤더 설정 방법

서버 측 주요 응답 헤더

  • Access-Control-Allow-Origin: 허용할 출처 지정
  • Access-Control-Allow-Origin: https://example.com Access-Control-Allow-Origin: * (모든 출처 허용)
  • Access-Control-Allow-Methods: 허용할 HTTP 메서드 지정
  • Access-Control-Allow-Methods: GET, POST, PUT, DELETE
  • Access-Control-Allow-Headers: 허용할 HTTP 헤더 지정
  • Access-Control-Allow-Headers: Content-Type, Authorization
  • Access-Control-Allow-Credentials: 인증 정보 허용 여부
  • Access-Control-Allow-Credentials: true
  • Access-Control-Max-Age: 예비 요청 캐시 시간(초)
  • Access-Control-Max-Age: 86400

구현 예제

Node.js + Express

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://example.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', 'true');
  
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  next();
});

Spring Boot

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOrigins("https://example.com")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("Content-Type", "Authorization")
            .allowCredentials(true)
            .maxAge(86400);
    }
}

Apache 서버 (.htaccess)

Header set Access-Control-Allow-Origin "https://example.com"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Max-Age "86400"
728x90
반응형