React + Springboot - CORS

김정훈·2024년 1월 9일
0
post-thumbnail

클라이언트 작업을 했을 때 가장 먼저 겪은 에러는 CORS 에러였습니다. 제 머리속에 강하게 박혀 대체 이 CORS가 뭔지에 대해 알아보려 합니다.

CORS에 대해

CORS란?
교차 출처 리소스 공유(Cross-origin resource sharing, CORS), 교차 출처 자원 공유는 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다.

origin = protocol + host + port를 말합니다. origin을 집 주소라고 생각하면 편한데요. 다시 말해 다른 집에서 들어오는 접근을 허용하는 정책입니다.

원래는 SOP 정책이다
다른 집에서 함부로 우리 집의 리소스를 공유하면 당연히 문제가 되겠죠? 그래서 브라우저는 SOP(Same-Origin-Policy)정책을 따릅니다. 하지만 점차 다른 출처간에 통신이 필요해져 CORS 정책을 새롭게 만듭니다.

어떤 흐름인가?

단순하다. Browser가 서버가 준 응답을 확인하여 허용된 오리진인지 검증하여 처리한다.

그래도 보안문제가 있지 않은지?
그렇다. 이를 위해 동작방식 3가지를 정했다.

  1. Simple Request
  • 위에서 언급한 흐름방식이다.
  • 클라이언트의 오리진이 서버가 허용한 오리진인지 비교하고 처리한다.
  • 단 한 번 주고받은 과정이기에 여러 조건이 붇는다.(메소드는 Get,Post,Head만 가능 등...)
  1. Preflight Request
  • HTTP 미리 전송해 실제 전송의 안전을 검증한다.
  • 이후에 Simple Request를 실시한다.
  1. Credentialed Request
  • Cookie, Authorization 등의 인증 정보가 필요할 때.
  • 요청 헤더에 xhr.withCredentials = true 설정을 합니다.

설정하기

Springboot에서 다음과 같이 설정합니다.

  1. Api에 특정 도메인 허용
@Slf4j
@RestController
@CrossOrigin(origins = "http://localhost:3000", exposedHeaders = "Authorization")
public class WriteController {
    @GetMapping("/write")
    public Map<String, String> write() {
        Map<String, String> hashMap = new HashMap<>();
        hashMap.put("message", "글쓰기");
        log.info("작업중");
        return hashMap;
    }
}

@CrossOrigin 설정

  1. Security를 사용중인 경우
    Security가 접근 권한의 최상위이기 때문에 SecurityConfig에 cors 설정을 하지 않으면 의미가 없습니다.
  @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
       return
               httpSecurity
                       .cors(cors -> cors.configurationSource(request -> {
                           var corsConfiguration = new CorsConfiguration();
                           if (request.getRequestURI().startsWith("/write")) {
                               corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000"));
                               corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
                               corsConfiguration.setAllowedHeaders(List.of("*"));
                           }
                               return corsConfiguration;
                       }))
                       ...

cors 설정을 처음 해보면 .cors(Customizer.withDefaults()) 설정을 할 수 있는데 이는 모든 api에 대해 cors를 허용하는 것이므로 관리가 힘듭니다.
따라서 위의 코드처럼 cors 허용을 원하는 api에 대해 조건을 걸어줍니다. method도 확장할 수 있습니다.
추가로 security에 cors 설정을 해주기만 하면 @CrossOrigin 설정이 적용이 되어서 위의 조건문에 해당하는 api가 아니더라고 @CrossOrigin이 설정된 api도 작동이 되는 것을 확인했습니다. 뭔가 설정이 중구난방이 되는 것 같아 마음에 들진 않았는데 Security에 모든 설정을 할 지, Controller에 설정을 추가로 할 지는 개인 취향인 것 같습니다.

읽어주셔서 감사하고 잘못된 점은 언제든지 태클 걸어주세요.

profile
백엔드 개발자

0개의 댓글