Cross-Origin Resource Sharing(CORS)은 추가적인 HTTP header를 사용해서 애플리케이션이 다른 origin의 리소스에 접근할 수 있도록 하는 메커니즘을 말한다.
허나 실제로는, 다른 origin에서 내 리소스에 함부로 접근하지 못하게 하기 위해 사용된다.
preflight
요청을 할 때 실제 요청에서 어떤 메서드를 사용할 것인지 서버에게 알리기 위해 사용된다.preflight
요청을 할 때 실제 요청에서 어떤 header를 사용할 것인지 서버에게 알리기 위해 사용된다.preflight
요청이 캐싱될 수 있는지를 나타낸다.Credentials
가 true일 때 요청에 대한 응답이 노출될 수 있는지를 나타낸다.preflight
요청에 대한 응답의 일부로 사용되는 경우 실제 자격 증명을 사용하여 실제 요청을 수행할 수 있는지를 나타낸다.preflight
되지 않으므로 자격 증명이 있는 리소스를 요청하면 헤더가 리소스와 함께 반환되지 않으면 브라우저에서 응답을 무시하고 웹 콘텐츠로 반환하지 않는다.preflight
요청에 대한 응답으로 허용되는 메서드들을 나타낸다.preflight
요청에 대한 응답으로 허용되는 header들을 나타낸다.만약 내가 서비스하고 있지 않은 사이트에서 세션을 요청해서 세션을 획득할 수 있다면 해당 사이트는 악의적으로 내 세션을 탈취하거나 다른 행동을 할 수 있다. 그래서 브라우저에서는 이러한 요청을 막는다.
피싱 사이트가 대표적인 공격 사례인데, 이러한 것을 막고 내가 허용한 origin들만 요청할 수 있도록 하기 위함이다.
브라우저가 리소스를 요청할 때, 추가적인 헤더에 정보를 담는다.(내 origin, 사용하는 메서드, 사용하는 헤더) -> 이 헤더를 서버에 보낸다. -> 서버는 서버가 응답할 수 있는 origin들을 헤더에 담아서 브라우저에게 보낸다. -> 브라우저는 이 헤더를 보고 해당 origin에서 요청할 수 있다면 리소스 전송을 한다.(불가능 하다면 에러 발생)
CORS
에러 발생 시 가장 쉬운 해결방안은 서버 단에서 특정 origin
혹은 모든 origin
을 허용하도록 설정해주기만 하면 된다.
다음은 Spring boot 기준 CORS 허용 방법 예시이다.
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
/*
http://localhost:8080에서 들어오는 모든 요청 CORS 허용
*/
@CrossOrigin(origins = "http://localhost:8080")
@PostMapping("/")
public String postSuccess(){
}
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 {
/*
http://localhost:8080 에서 들어오는 모든 요청 CORS 허용
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080");
}
}
preflight
는 우리말로 하면 말 그대로 미리 보내는 것, 사전 전달이라고 할 수
있다.
기본적으로 브라우저는 cross-origin
요청을 전송하기 전에 OPTIONS
메소드로 preflight
를 전송한다.
이 때, Response
로 Access-Control-Allow-Origin
과 Access-Control-Allow-Methods
가 넘어오는데 이는 서버에서 어떤 origin과 어떤 method를 허용하는지 브라우저에게 알려주는 역할을 한다.
브라우저가 결과를 성공적으로 확인하고 나면 가능한 origin들로부터 cross-origin
요청을 보내서 그 이후 과정을 진행한다.
그렇다면, cross-origin 요청을 보낼 때마다 preflight
요청 작업을 거쳐야 하는가?! 그건 아니다.
서버 설정을 통해서 preflight
결과의 캐시를 일정 기간동안 저장시킬 수 있다.
이 캐시 정보가 살아있는 시간 동안은 preflight
를 생략하고 바로 요청 전송이 가능하다.
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ApiController {
// maxAge=3600 설정을 통해 3600초 동안 preflight 결과를 캐시에 저장
@CrossOrigin(origins="http://localhost:8080", maxAge=3600)
@PostMapping("/")
public String postSuccess() {
return "REST API 호출 성공~!!";
}
}
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("/**")
.allowedOrigins("http://localhost:8080")
.maxAge(3600); // 3600초 동안 preflight 결과를 캐시에 저장
}
}