코딩과 결혼합니다

231026 - [Game_Crew]트러블슈팅 : CORS 설정하기 본문

코딩과 매일매일♥/Game_Crew

231026 - [Game_Crew]트러블슈팅 : CORS 설정하기

코딩러버 2023. 10. 26. 01:31
728x90

📌CORS (Cross-Origin Resource Sharing)

CORS는 출처가 다른 자원들을 공유한다는 뜻으로, 한 출처에 있는 자원에서 다른 출처에 있는 자원에 접근하도록 하는 개념이다. 다른 출처에 있는 자원을 요청하는 것을 교차 출처 요청이라 부른다.

교차 출처 리소스 공유
는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행한다.

📌출처

Protocol + Host + Port 3가지가 같으면 동일 출처(Origin)라고 한다.
다른 출처 요청일 경우, CORS 정책에 준수하여 요청해야만 정상적으로 응답을 받을 수 있다.


📌다른 출처 요청의 위험성

출처가 다른 두 애플리케이션이 자유로이 소통할 수 있는 환경은 꽤 위험하다. 만일 제약이 없다면, 해커가 CSRF나 XSS 등의 방법을 이용해서 우리가 만든 애플리케이션에서 해커가 심어놓은 코드가 실행하여 개인 정보를 가로챌 수 있다.

📌브라우저의 CORS 기본 동작

1. 클라이언트에서 HTTP 요청의 헤더에 Origin을 담아 전달한다.

2. 서버는 응답헤더에 Access-Control-Allow-Origin을 담아 클라이언트로 전달한다.

3. 클라이언트에서 Origin과 서버가 보내준 Access-Control-Allow-Origin을 비교한다.

만약 유효하지 않다면 그 응답을 사용하지 않고 버린다. (CORS 에러)


📌전역 설정으로 적용해 보기

문제 : CORS에러 발생
시도 : 구글 검색에서 나오는 레퍼런스들에서는 이제는 쓰지 않는 메서드나 클래스들을 사용하거나 나의
          SpringBoot 버전과는 호환되지 않아 CORS에러를 잡을 수 없었다.

해결 : Spring의 공식 문서를 통해 적용해 보았다. 
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // CSRF 설정
        http.csrf((csrf) -> csrf.disable());

        http.cors(Customizer.withDefaults());

        // 기본 설정인 Session 방식은 사용하지 않고 JWT 방식을 사용하기 위한 설정
        http.sessionManagement((sessionManagement) ->
                sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        );

        http.authorizeHttpRequests((authorizeHttpRequests) ->
                authorizeHttpRequests
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                        .requestMatchers("/user/**","/auth/**","/chat/**").permitAll() // '/api/user/'로 시작하는 요청 모두 접근 허가
                        .anyRequest().authenticated() // 그 외 모든 요청 인증처리
        );

        // 필터 관리
        http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class);
        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE"));
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
  • CSRF 설정 비활성화 - CSRF는 악의적인 웹 사이트가 인증된 사용자의 권한으로 요청을 보내는 것을 방지하는 보안기능이다. 
  • CORS 설정 : 다른 도메인에서의 요청에 대한 접근 제어를 설정할 수 있다.
  • 세션 관리 설정 : 세션 관리를 위해 SessionCreationPolicy.STATELESS로 설정한다. 이는 세션을 사용하지 않고 JWT(Json Web Token) 기반의 인증 방식을 사용하기 위함이다.
  • 요청 접근 제어 설정 :  특정 패턴의 요청에 대해 접근을 허용하거나 인증이 필요한 설정을 지정할 수 있다.
나는 단순한 클라이언트 요청, 개발 및 유지 관리의 단순화를 위해 비활성화를 시켰으며 추후에 보안을 위해 CSRF(Cross-Site Request Forgery)를 활성화 시켜볼 것이다.

CSRF를 활성화하려면 Spring Security 구성에서 몇 가지 추가적인 설정을 해주어야 한다.
1. CSRF 토큰을 사용하여 요청에 대한 검증을 활성화한다.
2. CSRF 토큰을 클라이언트에게 전달하기 위해 응답 헤더에 토큰을 포함시킨다.
3. 클라이언트에서 전달된 CSRF 토큰을 요청 헤더에 포함시킨다. 클라이언트는 이 헤더를 통해 CSRF 토큰을 서버로 전송해야 한다.
  • corsConfigurationSource 빈(Bean) 메서드
    • CORS의 구성을 설정하는 빈으로 주어진 설정에 따라 특정 도메인에서의 요청에 대한 접근을 제어한다.
    • 여기서는 "http://localhost:3000" 도메인에서의 GET, POST, PUT, DELETE 메서드를 허용하며, "Authorization", "Cache-Control", "Content-Type" 헤더를 허용하고, 자격 증명(인증 정보)을 허용한다.