예제를 살펴보자.

(이미지 출처: MDN)
https://domain-a.com의 프론트엔드 JavaScript 코드가 XMLHttpRequest를 사용하여 https://domain-b.com/data.json을 요청하는 경우 보안 상의 이유로, 브라우저는 스크립트에서 시작한 교차 출처 HTTP 요청을 제한한다.

XMLHttpRequest와 Fetch API는 동일 출처 정책을 따르기 때문에 이 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 한다.
Simple Request는 예비 요청(Preflight)을 과정 없이 바로 서버에 본 요청을 한 후, 서버가 응답의 헤더에 Access-Control-Allow-Origin과 같은 값을 전송하면 브라우저가 서로 비교 후 CORS 정책 위반 여부를 검사하는 방식이다.

브라우저는 요청을 한 번에 보내지 않고, 예비 요청과 본 요청으로 나누어 서버에 전달하는데, 브라우저가 예비 요청을 보내는 것을 Preflight라고 하며 이 예비 요청의 메소드에는 OPTIONS가 사용된다.
예비 요청의 역할은 본 요청을 보내기 전에 브라우저 스스로 안전한 요청인지 확인하는 것으로 요청 사양이 Simple Request에 해당하지 않을 경우 브라우저가 Preflight Request를 실행한다.

const headers = new Headers({
'Content-Type': 'text/xml',
});
fetch('https://auth-server/auth', { headers });

브라우저가 보낸 요청을 보면 Origin에 대한 정보 뿐만 아니라 예비 요청 이후에 전송할 본 요청에 대한 다른 정보들도 함께 포함되어 있다.
이 예비 요청에서 브라우저는 Access-Control-Request-Headers를 사용하여 자신이 본 요청에서 Content-Type 헤더를 사용할 것을 알려주거나, Access-Control-Request-Method를 사용하여 GET 메소드를 사용할 것을 서버에게 미리 알려주고 있다.

서버가 보내준 응답 헤더에 포함된 Access-Control-Allow-Origin: https://security.io의 의미는 해당 URL 외의 다른 출처로 요청할 경우에는 CORS 정책을 위반했다고 판단하고 오류 메시지를 내고 응답을 버리게 된다.
| URL | 동일 출처 | 근거 |
|---|---|---|
https://security.io/auth?username=user1 | O | 스킴, 호스트, 포트가 동일 |
https://user:password@security.io | O | 스킴, 호스트, 포트가 동일 |
http://security.io | X | 스킴이 다름 |
https://api.security.io | X | 호스트가 다름 |
https://security.io:8000 | ? | 브라우저의 구현에 따라 다름, explorer는 포트 자체를 무시함 |
CorsFilter를 추가한다.corsFilter라는 이름의 Bean이 제공되면 해당 필터가 사용된다.corsFilter라는 이름의 Bean이 없고 CorsConfigurationSource Bean이 정의된 경우 해당 Bean이 사용된다.CorsConfigurationSource Bean이 정의되어 있지 않은 경우 Spring MVC가 클래스 경로에 있으면 HandlerMappingIntrospector가 사용된다.CorsConfigurationSource를 통해 일치된 정책에 따라 CORS 응답 헤더와 같은 응답을 업데이트하기 위한 필터이다.@CorsOriginjavax.servlet에서 CORS 검사를 수행해야 하는 보안 제얀 조건에 유용한 필터이다.