Post

CORS

CORS란?

CORS(Cross-Origin Resource Sharing)는 웹 브라우저에서 동일 출처 정책(Same-Origin Policy)에 위배되는 리소스 요청을 허용하기 위한 보안 기능이다. 동일 출처 정책은 보안상의 이유로, 웹 페이지가 자신이 로드된 출처(origin)와 다른 출처의 자원에 접근하는 것을 기본적으로 제한한다. 이때 출처(origin)는 도메인, 프로토콜, 포트 번호로 구성된다.

Desktop

예를 들어, http://example.com에서 로드된 웹 페이지는 기본적으로 http://another.com에서 호스팅된 API에 직접 요청을 보낼 수 없다. 이러한 제한이 해제되면 보안 취약점이 생길 수 있기 때문에, 이를 관리하기 위해 CORS가 필요하다.

요청 방식에 따른 CORS 여부

태그를 통한 리소스는 기본적으로 Cross-Origin 정책을 지원한다.

  • <link> 태그의 href 에서 다른 사이트의 .css 리소스에 접근하는 것이 가능
  • <img> 태그의 src 에서 다른 사이트의 .png, .jpg 등의 리소스에 접근하는 것이 가능
  • <script> 태그의 src 에서 다른 사이트의 .js 리소스에 접근하는 것이 가능

2. XMLHttpRequest, Fetch API 스크립트

기본적으로 Same-Origin 정책을 따른다.

  • 다른 도메인의 소스에 대해 자바스크립트 ajax 요청 API 호출시
  • 웹 폰트 CSS 파일 내 @font-face에서 다른 도메인의 폰트 사용 시

3. 요청에 따른 결과 차이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
    <img src="https://third-party-test.glitch.me/check.svg" alt="이미지">

    <script>
        fetch('https://third-party-test.glitch.me/check.svg')
            .then(response => response.blob())
            .then(imgBlob => {
                const imageObjectURL = URL.createObjectURL(imgBlob); // 응답 받은 이미지를 blob 객체로 변환
                const img = document.createElement('img'); // 이미지 태그를 생성하고
                img.src = imageObjectURL; // 이미지 경로를 설정한뒤
                document.body.append(img); // html에 추가
            })
    </script>
</body>

태그를 이용하여 요청한 경우에는 사진을 불러오지만 fetch api 스크립트를 이용한 요청은 CORS error를 발생시킨다.

브라우저의 CORS 기본 동작

출처 구분은 서버가 하는 것이 아니라 브라우저에 구현된 스펙이다.

Desktop

서버에서 리소스 요청은 해주었으나 브라우저가 응답의 출처를 분석하여 동일 출처가 아니면 에러를 뱉는다. 이 때문에 CORS 에러가 브라우저에서만 뜨고 서버에서는 정상적인 응답이 발생했다고 뜨는 것이다. 브라우저의 CORS 기본 동작은 다음과 같다.

  1. 클라이언트에서 HTTP 요청의 헤더에 Origin을 담아 전달

기본적으로 웹은 HTTP 프로토콜을 이용하여 서버에 요청을 보내는데, 이때 브라우저는 요청 헤더에 Origin 이라는 필드에 출처를 함께 담아 보내게 된다.

Desktop

  1. 서버는 응답헤더에 Access-Control-Allow-Origin을 담아 클라이언트로 전달

서버는 이 요청에 대한 응답을 할 때 응답 헤더에 Access-Control-Allow-Origin 이라는 필드를 추가하고 값으로 해당 리로스에 접근하는 것이 허용된 출처 url을 내려보낸다.

Desktop

  1. 클라이언트에서 Origin과 서버가 보내준 Access-Control-Allow-Origin을 비교

응답을 받은 브라우저는 자신이 보냈던 요청의 Origin과 서버가 보낸준 응답의 Access-Control-Allow-Origin을 비교하고 차단할지 말지를 결정한다.

결국 CORS 해결책은 서버가 Access-Control-Allow-Origin의 헤더에 허용할 출처를 기재해서 클라이언트에 응답하면 해결 할 수 있는 문제이다.(벡엔드 개발자가 고쳐야될 부분이라는 것이다.)

Spring Security에서 CORS error 해결

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
public class WebConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                        .allowedOrigins("http://localhost:3000")
                        .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                        .allowedHeaders("*")
                        .allowCredentials(true);
            }
        };
    }
}

Spring에서 CORS error를 해결하기 위해서는 allowedOrigins에 서버가 허용할 클라이언트 출처를 기재한다. allowedOrigins는 서버가 특정 출처에서 온 요청을 허용할지를 결정하는 것이다. 위를 설정하면 Spring은 Access-Control-Allow-Origin 헤더를 통해 브라우저에게 “이 출처에서 온 요청은 허용된다”라고 알려주는 역할을 하게 된다.


참고 자료

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F

This post is licensed under CC BY 4.0 by the author.