728x90
CORS

- HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.
- 웹 애플리케이션이 리소스가 자신의 출처와 다를 때 브라우저는 요청 헤더에 Origin 필드에 요청 출처를 함께 담아 교차 출처 HTTP 요청을 실행한다.
- 출처를 비교하는 로직은 서버에 구현된 스펙이 아닌 브라우저에 구현된 스펙 기준으로 처리되며 브라우저는 클라이언트의 요청 헤더와 서버의 응답 헤더를 비교해서 최종 응답을 결정한다.
- 두 개의 출처를 비교하는 방법은 URL의 구성요소 중 Protocol, Host, Port 이 세 가지가 동일한지 확인하면 되고 나머지는 틀려도 상관없다.
-
https://domain-a.com의 프론트 엔드 JavaScript 코드가 XMLHttpRequest를 사용하여 https://domain-b.com/data.json을 요청하는 경우 보안 상의 이유로, 브라우저는 스크립트에서 시작한 교차 출처 HTTP 요청을 제한한다.
-
XMLHttpRequest와 Fetch API는 동일 출처 정책을 따르기 때문에 이 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 한다.
-
Simple Request

- Simple Request는 예비 요청(Prefilght)을 과정 없이 바로 서버에 본 요청을 한 후, 서버가 응답의 헤더에 Access-Control-Allow-Origin과 같은 값을 전송하면 브라우저가 서로 비교 후 CORS 정책 위반 여부를 검사하는 방식이다
- 제약 사항
- GET, POST, HEAD 중 한 가지 Method를 사용해야 한다.
- 헤더는 Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width만 가능하며, Custom Header는 허용되지 않는다.
- Content-type은 application/x-www-form-urlencoded, multipart/form-data, text/plain만 가능하다.
Preflight Request

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

- 브라우저가 보낸 요청을 보면 Origin에 대한 정보뿐만 아니라 예비 요청 이후에 전송할 본 요청에 대한 다른 정보들도 함께 포함되어 있는 것을 볼 수 있다.
- 이 예비 요청에서 브라우저는 Access-Control-Request-Headers 를 사용하여 자신이 본 요청에서 Content-Type 헤더를 사용할 것을 알려주거나, Access-Control-Request-Method를 사용하여 GET 메서드를 사용할 것을 서버에게 미리 알려주고 있다.
-
서버가 보내준 응답 헤더에 포함된 Access-Control-Allow-Origin: https://security.io의 의미는 해당 URL 외의 다른 출처로 요청할 경우에는 CORS 정책을 위반했다고 판단하고 오류 메시지를 내고 응답을 버리게 된다
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는 포트 자체 무시) |
CORS 해결
서버에서 Access-Control-Allow-* 세팅
- Access-Control-Allow-Origin : 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용한다
- *, https://security.io
- Access-Control-Allow-Methods : preflight request에 대한 응답으로 실제 요청 중에 사용할 수 있는 메서드를 나타낸다
- 기본값은 GET, POST, HEAD, OPTIONS, *
- Access-Control-Allow-Headers: preflight request에 대한 응답으로 실제 요청 중에 사용할 수 있는 헤더 필드 이름을 나타낸다
- 기본값은 Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Custom Header, *
- Access-Control-Allow-Credentials: 실제 요청에 쿠기나 인증 등의 사용자 자격 증명이 포함될 수 있음을 나타낸다. Client의 credentials:include 일 경우 true 필수
- Access-Control-Max-Age: preflight 요청 결과를 캐시 할 수 있는 시간을 나타내는 것으로 해당 시간 동안은 preflight요청을 다시 하지 않게 된다
CORS Configurer
- Spring Security 필터 체인에 CorsFilter를 추가한다.
- corsFilter라는 이름의 Bean이 제공되면 해당 CorsFilter가 사용된다
- corsFilter라는 이름의 Bean이 없고 CorsConfigurationSource 빈이 정의된 경우 해당 CorsConfiguration이 사용된다.
- CorsConfigurationSource 빈이 정의되어 있지 않은 경우 Spring MVC가 클래스 경로에 있으면 HandlerMappingIntrospector가 사용된다.
CORS Filter
- CORS 예비 요청을 처리하고 CORS 단순 및 본 요청을 가로채고, 제공된 CorsConfigurationSource를 통해 일치된 정책에 따라 CORS 응답 헤더와 같은 응답을 업데이트하기 위한 필터이다
- Spring MVC Java 구성과 Spring MVC XML 네임스페이스에서 CORS를 구성하는 대안이라 볼 수 있다 ( 예: @CorsOrigin)
- 스프링 웹에 의존하는 응용 프로그램이나 javax.servlet 에서 CORS 검사를 수행해야 하는 보안 제약 조건에 유용한 필터이다
구현
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests().anyRequest().authenticated();
http.cors().configurationSource(corsConfigurationSource()); //빈으로 만들 Configuration 빈을 작성한다
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("*");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
//configuration.setAllowCredentials(true);
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration); // 어떤 경로로 부터 오는 요청을 어떤 설정을 할건지 작성
return source;
}
}
- CorsConfigurationSource 같은 경우 인터페이스이고, 이를 구현한 것들 중 URL을 기준으로 설정하는 UrlBasedCorsConfigurationSource를 사용하였다.
- 해당 URL 패턴에 적용할 설정 파일을 setting 해주면 된다
- 설정 클래스 같은 경우 CorsConfiguraion 클래스이며, 여러 설정이 가능하다
- AllowedOrigin은 헤더에 작성된 URL만 (와일드카드 가능) 허용한다.
- AllowedMethod는 실제로 사용할 수 있는 메서드만 허용한다.
- AllowedHeader는 실제로 사용할 수 있는 헤더 필드 이름을 나타낸다
- AllowCredentials는 캐시를 사용한다.
- setMaxAge는 캐시의 유효한 시간을 설정한다
728x90
'스프링 시큐리티 OAuth2 > Spring Security Fundamentals' 카테고리의 다른 글
| HttpBasic 인증 (0) | 2022.12.18 |
|---|---|
| 시큐리티 인증 및 인가 흐름 요약 (0) | 2022.12.17 |
| AuthenticationEntryPoint 이해 (0) | 2022.12.17 |
| 자동 설정에 의한 초기화 진행 (0) | 2022.12.11 |
| 초기화 과정 이해(SecurityBuilder / SecurityConfigurer) (0) | 2022.12.02 |