CORS

Dev.Hammy·2024년 4월 7일
0

Spring MVC를 사용하면 CORS(Cross-Origin Resource Sharing)를 처리할 수 있습니다. 이 섹션에서는 이를 수행하는 방법을 설명합니다.

Introduction

반응형 스택에서 이에 상응하는 내용 보기

보안상의 이유로 브라우저는 현재 출처 외부의 리소스에 대한 AJAX 호출을 금지합니다. 예를 들어, 한 탭에는 은행 계좌를 두고 다른 탭에는 evil.com을 둘 수 있습니다. evil.com의 스크립트는 귀하의 자격 증명을 사용하여 은행 API에 AJAX 요청을 할 수 없어야 합니다. 예를 들어 귀하의 계좌에서 돈을 인출하는 경우입니다!

CORS(Cross-Origin Resource Sharing)는 IFRAME 또는 JSONP를 기반으로 하는 덜 안전하고 덜 강력한 해결 방법을 사용하는 대신 어떤 종류의 도메인 간 요청이 승인되는지 지정할 수 있도록 대부분의 브라우저에서 구현되는 W3C 사양입니다.

Credentialed Requests

반응형 스택에서 이에 상응하는 내용 보기

자격 증명 요청과 함께 CORS를 사용하려면 allowedCredentials를 활성화해야 합니다. 이 옵션은 구성된 도메인에 대해 높은 수준의 신뢰를 설정하고 쿠키 및 CSRF 토큰과 같은 민감한 사용자별 정보를 노출하여 웹 애플리케이션의 공격 표면을 증가시킵니다.

자격 증명을 활성화하면 구성된 "*" CORS 와일드카드가 처리되는 방식에도 영향을 줍니다.

  • allowOrigins에서는 와일드카드가 승인되지 않지만, 대신에 allowOriginPatterns 속성을 사용하여 동적 원본 집합과 일치시킬 수 있습니다.

  • allowedHeaders 또는 allowedMethods에 설정된 경우 Access-Control-Allow-HeadersAccess-Control-Allow-Methods 응답 헤더는 CORS 실행 전 요청에 지정된 관련 헤더 및 메서드를 복사하여 처리됩니다.

  • exposedHeaders에 설정된 경우 Access-Control-Expose-Headers 응답 헤더는 구성된 헤더 목록이나 와일드카드 문자로 설정됩니다. Access-Control-Allow-Credentialstrue로 설정된 경우 CORS 사양에서는 와일드카드 문자를 허용하지 않지만 대부분의 브라우저는 이를 지원하며 CORS 처리 중에 응답 헤더를 모두 사용할 수 있는 것은 아니므로 결과적으로 와일드카드 문자가 헤더가 됩니다. allowCredentials 속성 값에 관계없이 지정된 경우 사용되는 값입니다.

[Warning]
이러한 와일드카드 구성은 편리할 수 있지만 가능하면 더 높은 수준의 보안을 제공하기 위해 유한한 값 집합을 구성하는 것이 좋습니다.

Processing

반응형 스택에서 이에 상응하는 내용 보기

CORS 사양은 실행 전 요청, 단순 요청, 실제 요청을 구분합니다. CORS의 작동 방식을 알아보려면 이 기사 등을 읽어보거나 사양에서 자세한 내용을 확인하세요.

Spring MVC HandlerMapping 구현은 CORS에 대한 기본 지원을 제공합니다. 요청을 핸들러에 성공적으로 매핑한 후 HandlerMapping 구현은 지정된 요청 및 핸들러에 대한 CORS 구성을 확인하고 추가 조치를 취합니다. 실행 전 요청은 직접 처리되는 반면 단순하고 실제 CORS 요청은 가로채서 검증되고 필수 CORS 응답 헤더가 설정됩니다.

원본 간 요청을 활성화하려면(즉, Origin 헤더가 존재하고 요청 호스트와 다름) 명시적으로 선언된 CORS 구성이 있어야 합니다. 일치하는 CORS 구성이 없으면 실행 전 요청이 거부됩니다. 단순 CORS 요청과 실제 CORS 요청의 응답에는 CORS 헤더가 추가되지 않으므로 브라우저는 이를 거부합니다.

HandlerMapping은 URL 패턴 기반 CorsConfiguration 매핑을 사용하여 개별적으로 구성할 수 있습니다. 대부분의 경우 애플리케이션은 MVC Java 구성 또는 XML 네임스페이스를 사용하여 이러한 매핑을 선언하며, 이로 인해 단일 전역 맵이 모든 HandlerMapping 인스턴스에 전달됩니다.

HandlerMapping 수준의 전역 CORS 구성을 보다 세분화된 handler 수준 CORS 구성과 결합할 수 있습니다. 예를 들어 주석이 달린 컨트롤러는 클래스 또는 메서드 수준 @CrossOrigin 주석을 사용할 수 있습니다(다른 핸들러는 CorsConfigurationSource를 구현할 수 있음).

글로벌 구성과 로컬 구성을 결합하는 규칙은 일반적으로 추가적입니다. 예를 들어 모든 글로벌 원본과 모든 로컬 원본이 있습니다. 단일 값만 허용되는 속성의 경우. allowCredentialsmaxAge, 로컬이 전역 값을 재정의합니다. 자세한 내용은 CorsConfiguration#combine(CorsConfiguration)을 참조하세요.

[Tip]
소스에서 자세히 알아보거나 고급 사용자 정의를 수행하려면 뒤에 있는 코드를 확인하세요.

  • CorsConfiguration
  • CorsProcessor, DefaultCorsProcessor
  • AbstractHandlerMapping

@CrossOrigin

반응형 스택에서 이에 상응하는 내용 보기

@CrossOrigin annotation은 다음 예제와 같이 주석이 달린 컨트롤러 메서드에 대한 교차 출처 요청을 활성화합니다.

@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin
	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

기본적으로 @CrossOrigin은 다음을 허용합니다.

  • 모든 origins.

  • 모든 헤더.

  • 컨트롤러 메서드가 매핑되는 모든 HTTP 메서드입니다.

allowCredentials는 기본적으로 활성화되어 있지 않습니다. 이는 민감한 사용자별 정보(예: 쿠키 및 CSRF 토큰)를 노출하는 신뢰 수준을 설정하고 적절한 경우에만 사용해야 하기 때문입니다. 활성화되면 allowOrigins를 하나 이상의 특정 도메인(특수 값 "*"은 아님)으로 설정해야 하거나, 대신에 allowOriginPatterns 속성을 사용하여 동적 원본 집합과 일치시킬 수 있습니다.

maxAge는 30분으로 설정됩니다.

@CrossOrigin은 클래스 수준에서도 지원되며 다음 예제와 같이 모든 메서드에서 상속됩니다.

@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

다음 예제와 같이 클래스 수준과 메서드 수준 모두에서 @CrossOrigin을 사용할 수 있습니다.

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin("https://domain2.com")
	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

Global Configuration

반응형 스택에서 이에 상응하는 내용 보기

세분화된 컨트롤러 메서드 수준 구성 외에도 일부 전역 CORS 구성도 정의하고 싶을 수도 있습니다. 모든 HandlerMapping에서 URL 기반 CorsConfiguration 매핑을 개별적으로 설정할 수 있습니다. 그러나 대부분의 애플리케이션은 이를 수행하기 위해 MVC Java 구성 또는 MVC XML 네임스페이스를 사용합니다.

기본적으로 전역 구성은 다음을 활성화합니다.

  • 모든 기원.

  • 모든 헤더.

  • GET, HEADPOST 메소드.

allowCredentials는 기본적으로 활성화되어 있지 않습니다. 이는 민감한 사용자별 정보(예: 쿠키 및 CSRF 토큰)를 노출하는 신뢰 수준을 설정하고 적절한 경우에만 사용해야 하기 때문입니다. 활성화되면 AllowOrigins를 하나 이상의 특정 도메인(특수 값 "*"은 아님)으로 설정해야 하거나, 대신에 allowOriginPatterns 속성을 사용하여 동적 원본 집합과 일치시킬 수 있습니다.

maxAge는 30분으로 설정됩니다.

Java Configuration

반응형 스택에서 이에 상응하는 내용 보기

MVC Java 구성에서 CORS를 활성화하려면 다음 예제와 같이 CorsRegistry 콜백을 사용할 수 있습니다.

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

	@Override
	public void addCorsMappings(CorsRegistry registry) {

		registry.addMapping("/api/**")
			.allowedOrigins("https://domain2.com")
			.allowedMethods("PUT", "DELETE")
			.allowedHeaders("header1", "header2", "header3")
			.exposedHeaders("header1", "header2")
			.allowCredentials(true).maxAge(3600);

		// Add more mappings...
	}
}

XML Configuration

XML 네임스페이스에서 CORS를 활성화하려면 다음 예제와 같이 <mvc:cors> 요소를 사용할 수 있습니다.

<mvc:cors>

	<mvc:mapping path="/api/**"
		allowed-origins="https://domain1.com, https://domain2.com"
		allowed-methods="GET, PUT"
		allowed-headers="header1, header2, header3"
		exposed-headers="header1, header2" allow-credentials="true"
		max-age="123" />

	<mvc:mapping path="/resources/**"
		allowed-origins="https://domain1.com" />

</mvc:cors>

CORS Filter

반응형 스택에서 이에 상응하는 내용 보기

내장된 CorsFilter를 통해 CORS 지원을 적용할 수 있습니다.

[Note]
Spring Security와 함께 CorsFilter를 사용하려는 경우 Spring Security에는 CORS에 대한 지원이 내장되어 있다는 점을 명심하세요.

필터를 구성하려면 다음 예제와 같이 CorsConfigurationSource를 해당 생성자에 전달합니다.

CorsConfiguration config = new CorsConfiguration();

// Possibly...
// config.applyPermitDefaultValues()

config.setAllowCredentials(true);
config.addAllowedOrigin("https://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);

CorsFilter filter = new CorsFilter(source);

0개의 댓글