요약
직역하자면 교차 출처 자원 공유. 사용되는 의미는, 출처가 다른 자원에 대한 공유를 허용하는 [규칙]이다. CORS 규칙을 지키지 않은 요청에 대해서 막겠다는 의미.
출처라고 하면 스킴과 호스트, 포트를 의미한다. 예를 들면 https://naver.com:8080 이다. 이 경우 https 스킴에 naver.com 호스트이며 8080 포트로 들어온 요청만 받는다는 SOP(Same Origin Policy) 규칙에서 예외 조항을 설정한다면 그게 CORS 규칙이 될 것이다.
출처를 비교하는 스펙은 기본적으로 브라우저 스펙이다. 요청이 들어오면 서버로 요청하여 응답을 받고 출처를 비교해 SOP를 어겼다면 리젝한다. 브라우저를 통하지 않은 요청을 당연히 비교하지 않는다.
CORS 동작 방식
http요청을 예비요청(preflight)와 본요청으로 나누어진다.
http요청 시 최초 origin 이라는 항목을 헤더에 담아 예비 요청을 한다.
예비 요청을 하면 서버는 허용되는 규칙에 대해 응답하며 출처에 대한 값은 Access-Control-Allow-Origin 에 담겨있다.
예비 요청에 사용되는 함수는 OPTIONS로 origin 뿐만 아니라 여러 정보를 보내고 적절한 응답을 받게 되며 아래같은 정보를 담고 받는다.
요청
OPTIONS https://evanmoon.tistory.com/rss
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ko;q=0.8,ja;q=0.7,la;q=0.6
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: GET
Connection: keep-alive
Host: evanmoon.tistory.com
Origin: https://evan-moon.github.io
Referer: https://evan-moon.github.io/2020/05/21/about-cors/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
응답
OPTIONS https://evanmoon.tistory.com/rss 200 OK
Access-Control-Allow-Origin: https://evanmoon.tistory.com
Content-Encoding: gzip
Content-Length: 699
Content-Type: text/xml; charset=utf-8
Date: Sun, 24 May 2020 11:52:33 GMT
P3P: CP='ALL DSP COR MON LAW OUR LEG DEL'
Server: Apache
Vary: Accept-Encoding
X-UA-Compatible: IE=Edge
Simple Request
예비요청 없이 본요청만 보내고 CORS를 검사할 수 있으며 Simple Request라고 한다. 하지만 아무 때나 가능한 것은 아니며, 아래 조건을 충족해야한다.
- 요청의 메소드는 GET, HEAD, POST 중 하나여야 한다.
- Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안된다.
- 만약 Content-Type를 사용하는 경우에는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용된다.
Spring에서의 CORS 세팅 예제
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(Collections.singletonList("*")); // 허용할 Header
corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*")); // 허용할 URL
corsConfiguration.setAllowedMethods(
Arrays.asList("GET", "POST", "PUT", "DELETE")); // 허용할 Http Method
corsConfiguration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
자세한건 아래 참조
댓글