[WEB] CORS 에러란 ? ..

프로젝트가 끝나고 쉬고있는 와중에

백엔드 부분 하시던 부장급 개발자분이 이번에 리액트를 처음 하셔서 공부를 하시다가 이거 어떻게 하냐 질문을 했는데

CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

이런 에러가 떠있는걸 보고

"어? 이건 리액트가 아니라 백엔드에서 고치셔야 하는데요 ? ..."

대충 설명을 드렸는데도 이해를 못 하셔서 그냥 스프링 쪽 코드를 작성해서 보내드렸다..

CORS (Cross Origin Resource Sharing) 란 ?

우선 일반적으로 Spring 을 통해서 만든 주소 ex) localhost:8080
react를 통해 만든 주소 ex) localhost:3000
(앞에 http:// 프로토콜은 생략)

이렇게 백엔드의 주소와 프론트의 주소가 다르게 생성되는데

여기서 Origin (출처)는 프로토콜 + Host + Port 을 말하며
최신 브라우저에 공통적으로 있는 동일 출처 정책 때문인데

동일하지 않은 출처에서 리소스를 가져오게 될 경우 하이재킹이나 해킹을 당할 위험이 크기 때문에 최신 브라우저에선 CORS 에러를 통해 막고 있어

출처가 다른 경우의 리소스를 받기 위해선 CORS 즉 교차 출처 리소스 공유에 대한 설정이 필요한데

프록시 서버를 쓴다던지 CORS 정책을 꺼버린다던지 할 순 있지만 보안을 위해 생긴 정책을 마음대로 꺼버리는건 위험하기 때문에

해결책

  • 컨트롤러에 따라서 출처 허용을 주고싶다면
    @CrossOrigin(origins = "http://localhost:3000") // 특정 출처 허용

  • 전역적으로 출처 허용을 주고 싶다면

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**") // 모든 경로 허용
                        .allowedOrigins("http://localhost:3000") // 특정 출처 허용
                        .allowedMethods("GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드
                        .allowedHeaders("*") // 모든 헤더 허용
                        .allowCredentials(true); // 인증 정보 허용 (쿠키 등)
            }
        };
    }
}
  • Spring Security 를 사용한다면 ? (securityconfig)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

@Configuration  
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable()) // CSRF 비활성화
        .cors(cors -> {}) // CORS 활성화
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/**").permitAll() // API 요청 허용
            .anyRequest().authenticated()
        )
        .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

    return http.build();
}
}
  • spring boot 를 사용한다면? (properties 파일에서)
spring.web.cors.allowed-origins=http://localhost:3000
spring.web.cors.allowed-methods=GET,POST,PUT,DELETE
spring.web.cors.allowed-headers=*
spring.web.cors.allow-credentials=true

CORS 에러 같은 경우 프론트 단에서 사실상 해결 방안이 없는게 ...
프론트 단에 접근하기 전에 접속을 차단하는거라 백엔드 측에서 최대한 해결을 해야한다