본문 바로가기

TIL & WIL

WIL_220612_CORS 관련 내용 정리. 프론트 협업을 위한 필수 개념.

CORS 오류 문구 예시

예전에 회사에서도 이런 오류를 보았던 기억이 난다. 특정한 이유로 인하여

회원 가입을 하는 A라는 웹사이트가 있었고, 회원이 가입을 하려고 할 때 그 회원이 중복이 된 회원인지

체크를 하려면 B라는 웹 서버에 올라가있는 데이터베이스에서 값을 비교하여 다시 돌려줘야 하는 과정이 있었다.

그때만 하더라도 CORS라는것이 대체 어떤 오류인지 처음 보았기 때문에

이 문제를 해결하기 위해 여기저기 물어보며 해결했던 기억이 난다.

 

CORS란 정확히 무엇일까?

 

CORS는 Cross-Origin Resource Sharing의 약자로 여기서 말하는 Origin이란,

1) http 또는 https와 같은 프로토콜,

2) www.oooo.com 과 같은 도메인주소,

3) 80  또는 443 등의 포트 번호까지를 합쳐서 일컫는 말이다.

 

그 Origin이 Cross(교차, 서로 다른 것이 만남) 되었다는 것으로 유추해 볼 수 있듯이,

자기 자신이 속하지 않은 Origin에 리소스 요청을 보내면 웹 어플리케이션은 Cross-Origin Http 요청을

실행하게 된다. 이 때, 브라우저는 보안상의 이유로 <script> 안에서 시작되는 요청들을 제한한다.

<script></script>로 감싸진 script에서 생성된 Cross-Site HTTP Request는 Same-Origin-Policy(SOP)

적용받게 되어 해당 Request는 제한을 받게 되는 것이다.

 

예를 들어, 프론트엔드의 자바스크립트 코드가 https://oooo-a.com 에서 https://oooo-b.com 으로 

json 데이터 요청을 보낸다면 이것이 바로 Cross-Origin Http 요청인 것이며 이 요청은

다른 Origin으로부터의 응답이 올바른 CORS header를 '포함하지 않는다면'

위와 같은 에러 메시지를 보게 되는 것이다.

 

요즘은 AJAX라는 통신 방법이 널리 퍼지게 되면서 스크립트 안에서 생겨난 XML HTTP Request에서도

Cross-Site HTTP Request를 진행해야 할 경우와 필요성이 매우 커졌다. 그런 이유로 W3C(월드 와이드 웹 컨소시움)에서 

CORS라는 이름으로 새로운 표준을 내놓게 되었다. 기존에는 보안상의 이유로 XML HTTP Request가 자신과 동일한

도메인으로만 HTTP 요청을 보낼 수 있도록 제한하였으나, 웹 개발에서는 다른 도메인으로의 요청이

꼭 필요하다보니 Cross-Domain을 요청할 수 있도록 한 것이다.


Preflight Request란?

이미지 출처: https://www.popit.kr/cors-preflight-%EC%9D%B8%EC%A6%9D-%EC%B2%98%EB%A6%AC-%EA%B4%80%EB%A0%A8-%EC%82%BD%EC%A7%88/

 

W3C 명세에 의하면 브라우저는 먼저 서버에 Preflight request(예비 요청)를 전송하여 실제 요청을 보내는 것이 안전한지 OPTIONS method로 확인한다. 그리고 서버로부터 유효하다는 응답을 받으면 그 다음 HTTP request 메소드와 함께

Actual request(본 요청)을 보낸다. 만약 유효하지 않다면 에러를 발생시키고 실제 요청은 서버로 전송하지 않는다.

 

이러한 예비 요청과 본 요청에 대한 서버의 응답은 프로그래머가 구분지어 처리하는 것은 아니다.

프로그래머가 Access-Control- 계열의 Response Header만 적절히 정해주면 Options 요청으로 오는

예비 요청과 GET, POST, PUT, DELETE 등으로 오는 본 요청의 처리는 서버가 알아서 처리한다.

 


Simple Request란?

어떤 요청들은 CORS Preflight Request(사전 요청)을 발생시키지 않는데 보통 이런 요청들을 Simple Request라고 한다.

Simple Request의 경우에는 아래 3가지 조건이 모두 만족되는 경우를 말한다.

 

  • GET / HEAD / POST 중 한 가지 메소드를 사용해야 한다.
  • User agent에 의해 자동으로 설정되는 헤더(Connection, User-Agent 또는 Fetch spec에서 '금지된 헤더 이름(forbidden header name)'으로 정의된 이름들을 가진 헤더들)을 제외하고,
    Fetch spec에서 'CORS-safelisted request-header'라고 정의되어있고
    수동 설정이 허용된 헤더들은 다음과 같다.
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (but note the additional requirements below)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • 오직 아래의 Content Type만 지정해야 한다.
    • application / x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Spring Boot에서 CORS 에러를 피하는 방법

1. Configuration으로 해결하기

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:8080", "http://localhost:8081");
    }
}
  • config 패키지 안에 WebConfig라는 클래스를 만들어주고, 상단에 @Configuration 어노테이션을 붙여주어 설정파일이라는 것을 명시해준다. 
  • WebMvcConfigurer를 implements하고 addCorsMapping 메소드를 오버라이드 한다.
  • registry.addMapping을 이용하여 CORS를 적용할 URL 패턴을 적용할 수 있다. 위의 경우는 와일드 카드 사용(" /** ")
  • allowedOrigins 메소드를 이용하여 자원 공유를 허락할 Origin을 지정할 수 있다. 위 경우 처럼 한번에 여러개의
    Origin을 설정할 수도 있고 (" * ") 으로 모든 Origin을 허락할 수도 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST");
}
  • allowedMethods를 이용해서 허용할 HTTP Method를 지정할 수 있다. 마찬가지로 (" * ")를 이용하여
    모든 method를 허용할 수 있다.

 

 

2. Annotation 이용하기

@RequestMapping("/somePath")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class SomeController {
}
  • 위 처럼 CrossOrigin이라는 어노테이션을 사용하면 허용할 Origin이나 Methods를 좀 더 간편하게 지정할 수 있다.
    (origins, allowedHeaders, maxAge, methods 사용가능)
  • 어노테이션은 Class에 적용할 수도 있고, Method에 적용할 수도 있다.

<참고 블로그 및 출처>

https://valuefactory.tistory.com/1141

 

CORS란 무엇인가: CORS는 브라우저 하는 일

프로그래밍 공부를 하다보면 오픈 API에 요청보내고 응답받는 일을 굉장히 많이 하게 된다. 그러다보면 CORS 에러도 필연적으로 만나게 되는데, 대체 CORS란 무엇인가? 이미지 출처: https://developer.mo

valuefactory.tistory.com

https://dev-pengun.tistory.com/entry/Spring-Boot-CORS-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0#toc-Configuration%EC%9C%BC%EB%A1%9C%20%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0