Cross Origin Resource Sharing
브라우저에서 다른 출처의 리소스를 공유하는 방법
브라우저 정책 중 하나이다
URL 구성요소 중 Protocol
, Host
, Port
를 합친 것
ex, https://www.naver.com:8080
만약 두 URL에서 세 구성요소 (Protocol, Host, Port) 중 하나라도 다르다면 다른 출처로 인식한다.
대상 URL : https://ihoo.github.io/index
URL | 출처 | 이유 |
---|---|---|
https://ihoo.github.io/about | 일치 | - |
https://ihoo.github.io/about?q=work | 일치 | - |
https://ihoo.github.io/about#work | 일치 | - |
http://ihoo.github.io | 불일치 | Protocol 불일치 |
https://ihoo.github.io:81/about | 불일치 | Port 불일치 |
https://ihoo.heroku.com | 불일치 | Host 불일치 |
웹 브라우저 보안을 위해 같은 출처의 서버로만 자원을 공유(주고받도록)하도록 상호작용을 제안하는 보안 정책으로, 악의적인 자원을 분리하기위해 사용되는 브라우저 정책 이다
CORS는 이러한 SOP 로 인한 API 서버와의 자원공유의 어려움을 해결하기위해 나왔다.
즉, CORS 는 외부 자원을 사용하기위한 SOP 의 예외 조항 이다.
CORS 는 단순 요청 (SimpleRequest) 방식과 예비 요청(PreflightRequest) 방식이 있다.
둘 모두, Access-Control-Allow-Origin 을 통해 SOP 정책의 예와사항으로 둘 출처를 전달받아 이를 검증한다. 만약 헤더의 value 가 *
이라면, 모든 출처에 대한 허용(예외지정)을 의미한다.
서버에게 요청을 보내고, 서버에서 Access-Control-Allow-Origin
이라는 헤더를 포함한 응답을 브라우저에게 보낸다.
이후, 브라우저는 Access-Control-Allow-Origin
헤더를 확인해서 정책위반 여부를 판단한다.
서버로 전달하려는 리퀘스트가 단순 요청으로 동작하려면 아래 3가지 조건을 만족해야한다
application/x-www-form-urlencoded
, multipart/form-data
, text/plain
중 하나이어야한다.Accept
Accept-Language
Content-Language
Content-Type
DPR
Downlink
Save-Data
Viewport-Width
Width
서버에 예비 요청을 보내고, 안전성을 판단한 후, 본 요청(GET /resources) 를 보내는 방식이다.
안정성 판단 방법은 아래와 같다.
OPTION
메서드로 서버에 예비요청을 먼저 보낸 이후, 서버에서 Access-Control-Allow-Origin
헤더를 포함한 응답을 브라우저 보내면, 브라우저는 SingleRequest 와 동일한 방식으로 해당 해더를 확인하여, CORS 정책 위반 여부를 판단한다.
CORS 정책 위반으로 일어나는 문제상황을 CORS Issue
라고 한다.
SpringBoot 에서는 CORS 를 편하게 설정할 수 있도록 다음과 같은 Configuration 을 제공한다
@EnableWebSecurity
@Configuation
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//doSomething
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
//doSomething
.anyRequest().authenticated().and()
.cors().and();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
//doSomething
configuration.addAllowedOrigin("*");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
SpringSecurity 모듈은 기본적으로, 모든 인증되지 않은 요청에 대해 401 Error 를 반환한다
그러나, 이전에 서술하였던 예비 요청 방식의 CORS 정책 검증은 본 요청을 보내기 전, 인증헤더가 없는 예비 요청을 전송한다
따라서, 이러한 예비 요청에 대해 permitAll()
을 통해 인증 헤더 없이도 접근 가능하게 해놓지 않는다면, 예비 요청 방식으로 CORS 를 검증해야할 때 CORS Issue 가 발생할 위험이 높다
.cors().and();
SpringSecurity 에서 cors 를 적용한다는 뜻이다.
즉 Origin 헤더를 포함하는 모든 요청에 대해 인증 성공 여부와는 관계 없이, Access-Control-Allow-Origin
을 포함한 응답을 전송한다
public CorsConfigurationSource corsConfigurationSource()
CORS 정책에 대한 정보를 담고 있는 Bean 을 작성한다.
어떠한 자원을 SOP 예외(Cross-Origin) 로 처리할지 등을 설정한다.