CORS(Cross-Origin Resource Sharing)에 대한 이해와 설정 방법

KangWook·2024년 10월 6일

1. CORS란 무엇인가?

CORS(Cross-Origin Resource Sharing)는 웹 브라우저에서 도메인 간 리소스 요청을 제어하는 보안 메커니즘입니다. 즉, 브라우저는 한 도메인(origin)에서 다른 도메인(origin)의 리소스를 요청할 때 보안 규칙을 적용하는데, 이 과정에서 동작하는 규칙이 CORS입니다.

기본 원리
웹 애플리케이션은 기본적으로 동일 출처 정책(Same-Origin Policy)에 의해 보호됩니다. 동일 출처 정책은 다음 세 가지가 모두 일치하는 경우에만 리소스를 자유롭게 공유하도록 허용합니다:

  • 프로토콜 (http, https)
  • 호스트 (domain.com)
  • 포트 (:8080, :443 등)

2. CORS 작동 방식

CORS 요청이 일어날 때, 브라우저는 서버에 HTTP 요청을 보내며 "이 요청이 안전한지" 확인합니다. 서버는 특정 헤더를 응답에 포함하여 브라우저에게 "이 요청은 허용된다"고 알려줍니다. 브라우저는 이를 바탕으로 자원을 사용하도록 허가받습니다.

예: CORS 요청 흐름
클라이언트(브라우저)에서 API 요청을 보냅니다 (예: https://frontend.com에서 https://api.backend.com으로 요청).

서버(api.backend.com)는 응답에서 Access-Control-Allow-Origin 헤더를 포함시켜, 어느 도메인에서 접근이 가능한지 명시합니다.

Access-Control-Allow-Origin: https://frontend.com

브라우저는 응답에 포함된 Access-Control-Allow-Origin 값을 확인하고, 요청을 허용할지 결정합니다.

3. CORS 요청의 유형

CORS 요청에는 두 가지 주요 유형이 있습니다: 단순(Simple) 요청과 예비(Preflight) 요청.

1) 단순 요청(Simple Request)

HTTP 메서드가 GET, POST, HEAD이고, Content-Type이 일반적인 값(application/x-www-form-urlencoded, text/plain, multipart/form-data)인 경우에는 단순 요청으로 처리됩니다. 이 경우, 브라우저는 CORS 정책을 자동으로 처리하고, 서버는 Access-Control-Allow-Origin 헤더만 포함시키면 됩니다.

2) 예비 요청(Preflight Request)

CORS 요청이 안전하지 않은 메서드(PUT, DELETE 등) 또는 커스텀 헤더를 포함하는 경우, 브라우저는 먼저 서버에 OPTIONS 메서드로 예비 요청(Preflight Request)을 보내 서버가 이 요청을 허용할지 확인합니다. 서버는 이를 처리하고 CORS 정책에 맞는 응답을 반환해야 합니다.

예비 요청의 응답 헤더 예시:

Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

4. CORS 설정 방법 (Spring Boot 기준)

스프링 부트(Spring Boot)에서는 CORS를 쉽게 설정할 수 있습니다. 주로 두 가지 방법으로 설정 가능합니다.

1) Controller 레벨에서 CORS 설정
특정 컨트롤러나 핸들러 메서드에 대해서만 CORS를 허용하고 싶다면 @CrossOrigin 어노테이션을 사용할 수 있습니다.

@RestController
@RequestMapping("/api")
public class MyController {

    @CrossOrigin(origins = "https://frontend.com")  // 특정 도메인에만 허용
    @GetMapping("/data")
    public ResponseEntity<String> getData() {
        return ResponseEntity.ok("Hello, CORS!");
    }
}

이 설정은 특정 경로와 특정 메서드에만 적용되며, https://frontend.com 도메인에서만 접근할 수 있습니다.

2) Global CORS 설정 (전역 설정)
애플리케이션 전체에 대한 CORS 정책을 설정하고 싶다면 WebMvcConfigurer를 사용해 전역적으로 설정할 수 있습니다.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 모든 경로에 대해 CORS 허용
                .allowedOrigins("https://frontend.com")  // 특정 Origin 허용
                .allowedMethods("GET", "POST", "PUT", "DELETE")  // 허용할 HTTP 메서드
                .allowedHeaders("Content-Type", "Authorization")  // 허용할 헤더
                .allowCredentials(true);  // 쿠키나 인증 정보도 함께 전송 허용
    }
}

이 방식은 애플리케이션 전체에 적용되며, 모든 API 경로에서 지정한 도메인에 대해서만 CORS를 허용하게 됩니다.

5. CORS에서 발생할 수 있는 문제 및 해결 방법

1) CORS 정책 오류
브라우저에서 "CORS 정책 오류"가 발생할 수 있습니다. 이는 주로 서버가 요청한 Origin을 허용하지 않았기 때문입니다. 서버 응답에 Access-Control-Allow-Origin 헤더가 없거나 잘못된 경우에 이런 오류가 발생합니다.

Access to XMLHttpRequest at 'https://api.backend.com' from origin 'https://frontend.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

해결 방법:

서버에서 올바르게 Access-Control-Allow-Origin 헤더를 설정했는지 확인해야 합니다.
필요하다면, 예비 요청에 대한 처리를 추가로 설정해야 할 수 있습니다.

2) 쿠키 인증 관련 문제
만약 클라이언트가 쿠키나 인증 정보를 함께 보내려면, Access-Control-Allow-Credentials: true 설정을 추가로 해야 합니다. 이때 allowedOrigins는 와일드카드(*)를 사용할 수 없습니다.

registry.addMapping("/**")
        .allowedOrigins("https://frontend.com")
        .allowCredentials(true);  // 인증 정보 허용

6. 최신 동향과 Best Practice

보안 강화: CORS는 기본적으로 보안을 강화하는 기술이므로, 가능한 한 최소한의 도메인만 허용하는 것이 중요합니다. allowedOrigins에 모든 도메인(*)을 허용하는 것은 위험할 수 있습니다.
동적 CORS 처리: 복잡한 시스템에서는 사용자의 권한이나 상황에 따라 동적으로 CORS 정책을 적용할 수 있습니다.
HTTPS 사용: CORS는 보안과 밀접한 관련이 있으므로, 특히 민감한 데이터가 다뤄지는 경우에는 반드시 HTTPS 프로토콜을 통해 CORS 요청을 처리하는 것이 권장됩니다.

결론

CORS는 도메인 간 리소스 공유를 안전하게 허용하는 중요한 보안 메커니즘입니다. 스프링 부트에서는 @CrossOrigin 어노테이션이나 WebMvcConfigurer를 통해 쉽게 설정할 수 있으며, 올바르게 설정하지 않으면 클라이언트에서 CORS 오류가 발생할 수 있습니다.

profile
꾸준히 성장하는 개발자

0개의 댓글