CORS와 CORS 설정

2024. 3. 13. 02:12Spring/Spring Security

[ CORS ]

 서버 사이드 템플릿으로 작성하면 CORS 에러를 겪지 못한다. 하지만 다른 도메인, 같은 도메인이라도 다른 포트 번호를 가진 애플리케이션끼리 통신을 하면 CORS 에러를 겪을 수 있다. 그 이유는 Chrome이나 Safari 같은 브라우저가 다른 origin을 가지는 경우 CORS 기능으로 보호를 하려고 하기 때문이다.

 

 여기서 언급하는 다른 origin은 HTTP, HTTPS 같은 scheme이 다른 경우, 도메인 명이 다른 경우, 포트 번호가 다른 경우 모두 해당된다. 그 이유는 출처가 불분명한 애플리케이션끼리의 통신은 보안성 위험을 가지기 때문이다. 그래서 웹 브라우저가 애플리케이션을 도와 외부 공격자가 직접 서버측에 요청을 보내는 것을 차단하게 하여 보안적 기능을 제공하는 것이다.

 

그러면 프론트엔드에서 이 설정을 해줘야할까? 아니면 백엔드에서 이런 설정을 해주어야할까?라고 묻는다면 이건 백엔드의 담당이다. 서버측에서는 다른 애플리케이션과 통신하기 전에 웹 브라우저에게 허용된 출처를 알려주어야 하는 의무가 있다.

 

  뷰 애플리케이션과 서버 애플리케이션이 통신을 하기 전에 웹 브라우저는 요청하는 뷰 애플리케이션의 scheme, domain, port 정보가 담긴 pre-flight요청을 한다. 서버 측에서 이걸 받으면 이전에 등록한 cors관련 설정 정보를 찾아보고 통신이 허용된 곳이면 200 OK하고 웹 브라우저에게 답장한다. 그리고 나서 뷰 애플리케이션에서 한 요청을 브라우저는 서버 애플리케이션에게 전달하고 응답을 받아서 뷰 애플리케이션으로 넘겨준다. 그러면 화면에 원하는 장면이 나올 수 있는 것이다.

 

 그리고 CORS 설정이 되어 있는 서버에 요청을 보낼 땐 다음처럼 preflight 요청에 관한 응답도 개발자 모드에서 확인할 수 있다.


[ Spring Security에서의 cors 설정 ]

 앞에서 이야기와 달리 스프링 security에서의 방식은 간단하다. 우선 SecurityFilterChain을 새로 정의하고 해당 객체를 빈으로 등록해주면 된다. 내부에서는 HttpSecurity http를 재정의하되 cors 옵션 부분만 집중해서 보면 아래처럼 표현할 수 있다.

 

 corsConfigurationSource를 익명 클래스로 상속 받아 작성하면 origin 뿐만 아니라 허용된 origin 내에서도 메서드, Json을 JS에서 허용할 수 있는지, 헤더, preflight 캐싱 시간 등을 설정할 수 있다.

 

확인용 코드:

@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception{

    http.cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {
                @Override
                public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                    CorsConfiguration config = new CorsConfiguration();
                    config.setAllowedOrigins(Collections.singletonList("http://localhost:4200")); // 허용된 Origin
                    config.setAllowedMethods(Collections.singletonList("*")); // 허용된 HTTP 메서드
                    config.setAllowCredentials(true); // Json을 JS에서 처리할 수 있는가?
                    config.setAllowedHeaders(Collections.singletonList("*")); // 허용된 Header
                    config.setMaxAge(3600L); // preflight 캐싱 시간
                    return config;
                }
            }));
    return http.build();
}

 

[ 참고 자료 ]

Spring Security 6 초보에서 마스터되기 최신 강의! - Eazy Bytes