Loading...
Spring Framework Reference Documentation 7.0.2의 CORS의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
Spring WebFlux는 CORS (Cross-Origin Resource Sharing)를 처리할 수 있게 해줍니다. 이 섹션에서는 그 방법을 설명합니다.
보안상의 이유로, 브라우저는 현재 origin 외부의 리소스에 대한 AJAX 호출을 금지합니다. 예를 들어, 한 탭에는 당신의 은행 계좌가 있고 다른 탭에는 evil.com이 있을 수 있습니다.
evil.com의 스크립트는 당신의 자격 증명을 사용하여 은행 API에 AJAX 요청을 보내서는 안 됩니다. 예를 들어, 당신 계좌에서 돈을 인출하는 것과 같은 행위 말입니다!
Cross-Origin Resource Sharing (CORS)는 IFRAME이나 JSONP를 기반으로 한 덜 안전하고 덜 강력한 우회 방법 대신 어떤 종류의 cross-domain 요청이 허용되는지를 지정할 수 있게 해주는 대부분의 브라우저에 의해 구현된 W3C 명세입니다.
CORS 명세는 preflight, simple, actual 요청을 구분합니다. CORS가 어떻게 동작하는지 학습하려면 이 글 (및 기타 여러 자료)을 읽거나, 더 자세한 내용은 명세를 참고할 수 있습니다.
Spring WebFlux HandlerMapping 구현은 CORS에 대한 내장 지원을 제공합니다. 요청이 핸들러에
성공적으로 매핑된 후, HandlerMapping은 주어진 요청과 핸들러에 대한 CORS 설정을
확인하고 추가 작업을 수행합니다.
Preflight 요청은 직접 처리되는 반면, simple 및 actual CORS 요청은 가로채어 검증되고 필요한 CORS 응답 헤더가 설정됩니다.
Cross-origin 요청(Origin 헤더가 존재하고 요청의 호스트와 다른 경우)을 허용하려면
명시적으로 선언된 CORS 설정이 필요합니다. 일치하는 CORS 설정이 없으면
preflight 요청은 거부됩니다.
Simple 및 actual CORS 요청의 응답에는 CORS 헤더가 추가되지 않으며, 그 결과 브라우저는 이를 거부합니다.
각 HandlerMapping은 URL 패턴 기반의 CorsConfiguration 매핑으로
개별적으로 설정
할 수 있습니다. 대부분의 경우, 애플리케이션은 이러한 매핑을 선언하기 위해 WebFlux Java
설정을 사용하며, 이는 모든 HandlerMapping 구현에 전달되는 단일 global 맵을
생성합니다.
HandlerMapping 수준의 global CORS 설정을 보다 세밀한 핸들러 수준의 CORS
설정과 결합할 수 있습니다. 예를 들어, 어노테이션 기반 컨트롤러는 클래스 또는
메서드 수준의 @CrossOrigin 어노테이션을 사용할 수 있습니다 (다른 핸들러는
CorsConfigurationSource를 구현할 수 있습니다).
Global과 local 설정을 결합하는 규칙은 일반적으로 더해지는 방식입니다. 예를 들어, 모든 global origin과 모든 local origin이 합쳐집니다.
allowCredentials와 maxAge처럼
단일 값만 허용되는 속성의 경우 local 값이 global 값을 오버라이드합니다. 더 자세한 내용은
CorsConfiguration#combine(CorsConfiguration)
을 참고하십시오.
소스에서 더 배우거나 고급 커스터마이제이션을 수행하려면 다음을 참고하십시오:<br>-
CorsConfiguration<br><br>-CorsProcessor및DefaultCorsProcessor<br><br>-AbstractHandlerMapping
Credentialed 요청과 함께 CORS를 사용하려면 allowedCredentials를 활성화해야 합니다. 이
옵션은 설정된 도메인에 대해 높은 수준의 신뢰를 설정하며, 쿠키 및 CSRF 토큰과
같은 민감한 사용자별 정보를 노출함으로써 웹 애플리케이션의 공격 표면을 증가시킨다는 점에
유의해야 합니다.
Credential을 활성화하면 설정된 "*" CORS 와일드카드가 처리되는 방식에도 영향을
줍니다:
와일드카드는 allowOrigins에서 허용되지 않지만, 대신 allowOriginPatterns 프로퍼티를
사용하여 동적인 origin 집합과 매칭할 수 있습니다.
allowedHeaders 또는 allowedMethods에 설정된 경우, Access-Control-Allow-Headers
및 Access-Control-Allow-Methods 응답 헤더는 CORS preflight 요청에 지정된 관련
헤더와 메서드를 복사하여 처리됩니다.
exposedHeaders에 설정된 경우, Access-Control-Expose-Headers 응답 헤더는
설정된 헤더 목록 또는 와일드카드 문자로 설정됩니다. CORS 명세는
Access-Control-Allow-Credentials가 true로 설정된 경우 와일드카드 문자를 허용하지
않지만, 대부분의 브라우저는 이를 지원하며, CORS 처리 중에는 모든 응답 헤더를
사용할 수 없기 때문에, 그 결과 와일드카드 문자는 allowCredentials 프로퍼티의 값과
상관없이 지정된 경우 헤더 값으로 사용됩니다.
이러한 와일드카드 설정은 편리할 수 있지만, 가능한 경우 더 높은 수준의 보안을<br>제공하기 위해 유한한 값 집합을 설정하는 것이 권장됩니다.
@CrossOrigin@CrossOrigin
어노테이션은 다음 예제에서 보듯이 어노테이션된 컨트롤러 메서드에서 cross-origin 요청을
허용합니다:
1@RestController 2@RequestMapping("/account") 3public class AccountController { 4 5 @CrossOrigin 6 @GetMapping("/{id}") 7 public Mono<Account> retrieve(@PathVariable Long id) { 8 // ... 9 } 10 11 @DeleteMapping("/{id}") 12 public Mono<Void> remove(@PathVariable Long id) { 13 // ... 14 } 15}
1@RestController 2@RequestMapping("/account") 3class AccountController { 4 5 @CrossOrigin 6 @GetMapping("/{id}") 7 suspend fun retrieve(@PathVariable id: Long): Account { 8 // ... 9 } 10 11 @DeleteMapping("/{id}") 12 suspend fun remove(@PathVariable id: Long) { 13 // ... 14 } 15}
기본적으로, @CrossOrigin은 다음을 허용합니다:
allowCredentials는 기본적으로 활성화되어 있지 않은데, 이는 쿠키 및 CSRF 토큰과 같은
민감한 사용자별 정보를 노출하는 신뢰 수준을 설정하며 적절한 경우에만 사용해야 하기
때문입니다. 이를 활성화하는 경우 allowOrigins는 하나 이상의 특정 도메인 (특수 값 "*"
는 제외)으로 설정해야 하며, 또는 대신 allowOriginPatterns 프로퍼티를 사용하여 동적인
origin 집합과 매칭할 수 있습니다.
maxAge는 30분으로 설정됩니다.
@CrossOrigin은 클래스 수준에서도 지원되며 모든 메서드에 상속됩니다.
다음 예제는 특정 도메인을 지정하고 maxAge를 한 시간으로 설정합니다:
1@CrossOrigin(origins = "https://domain2.com", maxAge = 3600) 2@RestController 3@RequestMapping("/account") 4public class AccountController { 5 6 @GetMapping("/{id}") 7 public Mono<Account> retrieve(@PathVariable Long id) { 8 // ... 9 } 10 11 @DeleteMapping("/{id}") 12 public Mono<Void> remove(@PathVariable Long id) { 13 // ... 14 } 15}
1@CrossOrigin("https://domain2.com", maxAge = 3600) 2@RestController 3@RequestMapping("/account") 4class AccountController { 5 6 @GetMapping("/{id}") 7 suspend fun retrieve(@PathVariable id: Long): Account { 8 // ... 9 } 10 11 @DeleteMapping("/{id}") 12 suspend fun remove(@PathVariable id: Long) { 13 // ... 14 } 15}
다음 예제에서 보듯이, @CrossOrigin은 클래스와 메서드 수준 모두에서 사용할 수 있습니다:
1@CrossOrigin(maxAge = 3600) // (1) 2@RestController 3@RequestMapping("/account") 4public class AccountController { 5 6 @CrossOrigin("https://domain2.com") // (2) 7 @GetMapping("/{id}") 8 public Mono<Account> retrieve(@PathVariable Long id) { 9 // ... 10 } 11 12 @DeleteMapping("/{id}") 13 public Mono<Void> remove(@PathVariable Long id) { 14 // ... 15 } 16}
| 1 | 클래스 수준에서 @CrossOrigin 사용. |
| 2 | 메서드 수준에서 @CrossOrigin 사용. |
1@CrossOrigin(maxAge = 3600) // (1) 2@RestController 3@RequestMapping("/account") 4class AccountController { 5 6 @CrossOrigin("https://domain2.com") // (2) 7 @GetMapping("/{id}") 8 suspend fun retrieve(@PathVariable id: Long): Account { 9 // ... 10 } 11 12 @DeleteMapping("/{id}") 13 suspend fun remove(@PathVariable id: Long) { 14 // ... 15 } 16}
| 1 | 클래스 수준에서 @CrossOrigin 사용. |
| 2 | 메서드 수준에서 @CrossOrigin 사용. |
세밀한 컨트롤러 메서드 수준의 설정 외에도, 일부 global CORS 설정을
정의하고 싶을 수 있습니다. URL 기반의 CorsConfiguration 매핑을 개별적으로
HandlerMapping마다 설정할 수 있습니다.
그러나 대부분의 애플리케이션은 이를 위해 WebFlux Java 설정을 사용합니다.
기본적으로 global 설정은 다음을 활성화합니다:
GET, HEAD, POST 메서드.allowedCredentials는 기본적으로 활성화되어 있지 않은데, 이는 쿠키 및 CSRF 토큰과 같은
민감한 사용자별 정보를 노출하는 신뢰 수준을 설정하며 적절한 경우에만 사용해야 하기
때문입니다. 이를 활성화하는 경우 allowOrigins는 하나 이상의 특정 도메인 (특수 값 "*"
는 제외)으로 설정해야 하며, 또는 대신 allowOriginPatterns 프로퍼티를 사용하여 동적인
origin 집합과 매칭할 수 있습니다.
maxAge는 30분으로 설정됩니다.
WebFlux Java 설정에서 CORS를 활성화하려면 다음 예제에서 보듯이 CorsRegistry
콜백을 사용할 수 있습니다:
1@Configuration 2@EnableWebFlux 3public class WebConfig implements WebFluxConfigurer { 4 5 @Override 6 public void addCorsMappings(CorsRegistry registry) { 7 8 registry.addMapping("/api/**") 9 .allowedOrigins("https://domain2.com") 10 .allowedMethods("PUT", "DELETE") 11 .allowedHeaders("header1", "header2", "header3") 12 .exposedHeaders("header1", "header2") 13 .allowCredentials(true).maxAge(3600); 14 15 // Add more mappings... 16 } 17}
1@Configuration 2@EnableWebFlux 3class WebConfig : WebFluxConfigurer { 4 5 override fun addCorsMappings(registry: CorsRegistry) { 6 7 registry.addMapping("/api/**") 8 .allowedOrigins("https://domain2.com") 9 .allowedMethods("PUT", "DELETE") 10 .allowedHeaders("header1", "header2", "header3") 11 .exposedHeaders("header1", "header2") 12 .allowCredentials(true).maxAge(3600) 13 14 // Add more mappings... 15 } 16}
WebFilter내장된
CorsWebFilter를 통해 CORS 지원을 적용할 수 있으며,
이는 함수형 엔드포인트와 잘 맞습니다.
Spring Security와 함께
CorsFilter를 사용하려는 경우, Spring Security가 CORS에 대한<br>내장 지원을 제공한다는 점을 기억하십시오.
필터를 설정하려면, 다음 예제에서 보듯이 CorsWebFilter 빈을 선언하고
CorsConfigurationSource를 생성자에 전달하면 됩니다:
1@Bean 2CorsWebFilter corsFilter() { 3 4 CorsConfiguration config = new CorsConfiguration(); 5 6 // Possibly... 7 // config.applyPermitDefaultValues(); 8 9 config.setAllowCredentials(true); 10 config.addAllowedOrigin("https://domain1.com"); 11 config.addAllowedHeader("*"); 12 config.addAllowedMethod("*"); 13 14 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 15 source.registerCorsConfiguration("/**", config); 16 17 return new CorsWebFilter(source); 18}
1@Bean 2fun corsFilter(): CorsWebFilter { 3 4 val config = CorsConfiguration() 5 6 // Possibly... 7 // config.applyPermitDefaultValues() 8 9 config.allowCredentials = true 10 config.addAllowedOrigin("https://domain1.com") 11 config.addAllowedHeader("*") 12 config.addAllowedMethod("*") 13 14 val source = UrlBasedCorsConfigurationSource().apply { 15 registerCorsConfiguration("/**", config) 16 } 17 return CorsWebFilter(source) 18}
Range Requests
API Versioning