CORS (Cross-Origin Resource Sharing)이란?

maketheworldwise·2022년 5월 3일
0


이 글의 목적?

스프링 공식 문서에 나와있는 CORS에 대한 내용도 살펴보자.

CORS?

문서의 소개글을 보자. 해석하자면 - 보안적인 이유로 브라우저는 현재의 출처에서 외부의 자원을 요청하는 AJAX 요청을 금지하고 있다. 예를 들어, 한 개의 탭에는 은행 계좌가 있고 한 개의 탭에는 악의적인 사이트가 있다고 해보자. 악의적인 사이트는 AJAX 요청을 만들어 너의 자격으로 계좌에서 돈을 뽑는 은행 API에 보낼 수 없다.

그래서 무슨 의미일까?

CORS는 한국말로 교차 출처 리소스 공유로 한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제다. 그리고 이러한 교차 출처 리소스 공유는 보안을 고려해 금지하는 편이다. 내가 참고한 레퍼런스에서 가져온 이미지를 보면 한번에 이해할 수 있다.

요청별 특징

CORS는 Preflight, Simple, Credential 중 어떤 요청인지에 따라서 달라진다. 해당 내용에 대해서는 문서에서 생략되어있으니, 내가 알아본 내용만 간단하게 정리해보자.

Preflight 요청

Preflight 요청은 예비 요청을 미리 전송하여 실제 요청을 보내는 것이 안전한지 OPTIONS 메서드로 확인한다. 그리고 서버에서 유효하다는 응답을 받게되면 실제 요청을 보내고, 그렇지 않을 경우에는 에러를 발생시켜 실제 요청을 보내지 않는다.

Simple 요청

말그대로 단순한 요청이다. 예비 요청을 보내지 않은 형태의 요청을 의미하고 3가지 조건이 모두 만족해야 Simple 요청이라고 한다.

  • GET, POST, HEAD 중 한 가지 메소드를 사용
  • User-Agent에 의해 자동으로 설정되는 헤더를 제외한 헤더를 사용
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width

Credential 요청

HTTP Cookie와 Authentication 정보를 인식할 수 있게 해주는 요청이다. 기본적으로 브라우저는 Non-Credential로 설정되어있기 때문에 Credential 전송을 위해서는 부가적인 설정이 필요하다. 어떤 내용이 필요한지에 대해서는 지금 당장 필요하지 않으니 생략하기로 하자.

스프링 MVC에서의 CORS

문서에서 말하길 - 스프링 MVC HandlerMapping 구현체는 이미 CORS에 대해 제공을 하고 있다. 요청을 Handler에 성공적으로 Mapping이 완료되면 HandlerMapping 구현체가 요청에 대해 CORS 설정을 확인한다.

CORS를 허용하기 위해서는 명시적으로 CORS 설정을 해주어야 한다. 만약 구성한 CORS 설정이 없다면, Preflight 요청은 거부된다. Simple 요청이거나 실제 CORS 요청일 때 CORS 헤더가 없을 경우에는 브라우저는 거부한다.

각 HandlerMapping은 각각의 URL 패턴에 따라 구성하거나 글로벌하게 설정할 수 있다. 혹은 메소드 레벨에서 @CrossOrigin 어노테이션을 이용하여 설정이 가능하다. 대부분의 경우에는 자바 설정파일이나 XML을 이용하여 정의한다고 한다.

@CrossOrigin 설정

이 어노테이션을 이용하면 CORS 요청을 허용시킬 수 있다.

@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin
    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

기본적으로는 allowCredentials를 제외한 하단의 항목들을 모두 허용하고 있다.

  • 모든 출처
  • 모든 헤더
  • 모든 Controller에 Mapping된 HTTP 메소드

글로벌 설정

글로벌 설정은 앞에서 언급했듯이 대부분 자바 설정 파일이나 XML 파일로 설정한다고 한다.

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/api/**")
            .allowedOrigins("https://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(true).maxAge(3600);

        // Add more mappings...
    }
}
<mvc:cors>

    <mvc:mapping path="/api/**"
        allowed-origins="https://domain1.com, https://domain2.com"
        allowed-methods="GET, PUT"
        allowed-headers="header1, header2, header3"
        exposed-headers="header1, header2" allow-credentials="true"
        max-age="123" />

    <mvc:mapping path="/resources/**"
        allowed-origins="https://domain1.com" />

</mvc:cors>

기본적으로는 allowCredentials를 제외한 하단의 항목들을 허용하고 있다.

  • 모든 출처
  • 모든 헤더
  • GET, POST, HEAD 메소드

(추가적으로 CORS 필터를 추가할 수도 있는데, 해당 내용에 대해서는 생략한다.)

이 글의 레퍼런스

profile
세상을 현명하게 이끌어갈 나의 성장 일기 📓

0개의 댓글