[DEV] 기록

CORS 개요

꾸준함. 2023. 12. 21. 04:01

CORS (Cross-Origin Resource Sharing)

  • javascript로 요청 시 HTTP Header를 통해 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제
    • 여기서 출처란 프로토콜, 호스트, 그리고 포트의 집합을 의미
    • 포트를 명시적으로 선언할 때는 브라우저 구현에 따라 다른데 explorer의 경우 포트 자체를 무시
    • 서버는 SpringBoot, 클라이언트는 리액트로 구현할 때 포트가 서로 다르므로 프로토콜 및 호스트가 같더라도 CORS 처리 필요 ex) localhost:8080, localhost:3000
    • 출처만 같다면 query parameter 및 path parameter는 상관없음
  • 웹 애플리케이션이 요청하는 리소스가 자신의 출처와 다를 때 브라우저는 요청 헤더에 Origin 필드에 요청 출처를 함께 담아 Cross-Origin HTTP 요청 실행
  • 출처를 비교하는 로직은 브라우저에 구현된 스펙 기준으로 처리되며 브라우저는 클라이언트의 요청 헤더와 서버의 응답 헤더를 비교해서 최종 응답을 결정

 

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/cors_principle.png

 

 

CORS 요청 유형

 

CORS 요청 유형은 아래와 같이 두 가지로 나뉩니다.

  • Simple Request
  • Preflight Request

 

Preflight Request

  • 브라우저 요청을 보낼 때 후술할 특정 제약 사항을 충족하지 못할 경우 한 번에 보내지 않고 예비 요청과 본 요청으로 나누어 서버에 전달
  • 이때 예비 요청을 Preflight Request라고 하고 메서드에는 OPTIONS 사용
  • Preflight Request를 보면 다양한 정보들이 포함되어 있으며 Access-Control-Request-Headers를 사용하여 자신이 본 요청에서 Content-Type 헤더를 사용할 것을 알려주거나 Access-Control-Request-Method를 통해 사용할 메서드를 서버에 미리 알려줌
  • Request Headers 내 Origin, Access-Control-Request-Headers, 그리고 Access-Control-Request-Method와 Response Headers 내 Access-Control-Allow-Origin, Access-Control-Request-Headers, 그리고 Access-Control-Request-Method 일치 여부를 확인하는 HTTP 요청

 

preflight request
preflight request

 

Simple Request

CORS 요청을 할 때 아래의 제약 사항을 충족하면 앞서 언급한 Preflight Request를 생략하고 바로 본 요청인 Simple Request를 호출합니다.

  • GET, POST, HEAD 중의 한 가지 Method를 사용
  • 헤더는 Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width만 가능하고 Custom Header는 허용 X
  • Content-Type은 application/x-www-form-urlencoded, multipart/form-data, 그리고 text/plain만 가능

 

preflight request 없이 simple request만
simple request

 

 

CORS를 해결하기 위한 서버 내 설정

 

앞서 Response Headers에서 볼 수 있었다시피 서버에서 Access-Control-Allow-*를 어떻게 설정하냐에 따라 CORS 정책 위반 여부를 판별할 수 있습니다.

설정 내용은 아래와 같습니다.

  • Access-Control-Allow-Origin: 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용
  • 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: 실제 요청에 쿠키나 인증 등의 사용자 자격 증명이 포함될 수 있음을 나타냄
    • true로 설정 시 Access-Control-Allow-Origin을 와일드카드(*)로 설정할 수 없는 제약 사항 존재
  • Access-Control-Max-Age: preflight 요청 시 결과를 캐시 할 수 있는 시간을 나타내는 것으로 해당 시간 동안은 preflight 요청을 다시 하지 않게 됨

 

간단한 SpringBoot 예시

SpringBoot 프로젝트에서 CORS 정책을 적용하는 방법은 아래와 같이 두 가지가 있습니다.

  • spring-security 적용 시 CorsConfigurer 적용
  • spring-security 미적용 시 @CrossOrigin 어노테이션 적용

 

spring-security 적용 시

 

spring-security 적용 시 CORS preflight과 simple request는 아래와 같이 처리됩니다.

  • Spring Security 필터 체인에 CorsFilter 추가하여 처리
    • CorsFilter는 CORS preflight request 및 simple request를 가로채고 제공된 CorsConfigurationSource를 통해 일치된 정책에 따라 CORS Response Header와 같은 응답을 업데이트하기 위한 필터
  • corsFilter라는 이름의 Bean이 제공될 경우 CorsFilter가 사용
  • corsFilter라는 이름의 Bean이 없고 CorsConfigurationSource Bean이 정의된 경우 해당 CorsConfiguration이 사용됨
  • corsFilter, corsConfigurationSource 빈 둘 다 정의되어 있지 않지만 Spring MVC가 클래스 경로에 있을 경우 HandlerMappingInterceptor 사용

 

localhost:8082/index.html에서 localhost:8080/sample api를 요청한다고 가정했을 때 CORS 정책 허용을 위해 아래와 같이 설정이 가능합니다.


 

spring-security 미적용 시

 

Spring Framework 4.2 버전부터 @CrossOrigin 어노테이션을 통해 CORS 설정이 가능합니다.

@CrossOrigin 어노테이션은 개별 메서드 혹은 클래스에 설정할 수 있으며 별도 설정이 없을 경우 '모든 도메인 및 모든 요청 방식'에 대해 허용합니다.


 

참고

인프런 - 스프링 시큐리티 OAuth2 (정수원 강사님)

반응형