[보안/네트워크] CORS (Cross-Origin Resource Sharing) & 해결 방법 (Spring Boot)

전윤혁·2024년 8월 4일

Network Security

목록 보기
2/6

CORS (Cross-Origin Resource Sharing)

CORS(Cross-Origin Resource Sharing)는 웹 브라우저와 서버 간의 보안 메커니즘으로, 서로 다른 도메인, 프로토콜, 또는 포트 간에 리소스를 공유할 수 있도록 허용하는 방법을 정의한다.


1. CORS 에러란?

보통 프론트엔드와 백엔드로 나누어 프로젝트를 진행할 때 CORS 에러를 처음 맞닥뜨리게 된다.

예를 들어, 프론트엔드가 http://localhost:3000에서 실행되고 백엔드가 http://localhost:8080에서 실행되는 경우, 브라우저는 다른 출처로 리소스를 요청하게 된다. 이때, 브라우저는 보안상의 이유로 Same Origin Policy(동일 출처 정책)을 적용하여 이러한 요청을 차단하고, 이것이 CORS 에러의 발생 원인이라고 할 수 있다.

그렇다면 Same Origin Policy란 무엇일까?

여기서 Origin(출처)란 다음의 세 가지를 의미한다.

  • 프로토콜 (Protocol)
  • 호스트 (Host)
  • 포트 (Port)

따라서, Same Origin Policy는 말 그대로 프로토콜, 호스트, 포트가 모두 같은 리소스에만 접근을 허용하는 정책이다.


2. Same Origin Policy 예시

http://www.flicker.cxx/galleries/라는 URL을 기준으로, 각 예시가 같은 출처인지 아닌지 확인해보자.

URL Same origin?

  • https://www.flicker.cxx/galleries/
    NO, protocol

  • http://www.flickers.cxx/galleries/
    NO, domain

  • http://my.flickers.cxx/galleries/
    NO, domain

  • http://m.www.flickers.cxx/galleries/
    NO, domain

  • http://www.flicker.cxx:8080/galleries/
    NO, port [but IE]

    IE(Internet Explorer)는 동일 출처 정책 검사에 포트를 포함하지 않는다.

  • http://www.flicker.cxx/favorite/
    YES

  • http://www.flicker.cxx/favorite/aa.html
    YES


3. Same Origin Policy 사용 이유

그러면 Same Origin Policy, 이하 SOP는 왜 필요한걸까?

SOP은 웹 보안의 핵심 원칙으로, 악의적인 웹 사이트가 다른 도메인의 데이터를 무단으로 액세스하거나 조작하지 못하도록 방지한다.

예를 들어, 사용자가 신뢰할 수 있는 은행 웹사이트에 로그인한 상태에서 악성 웹사이트를 방문했을 때, 악성 웹사이트가 은행의 세션 쿠키에 접근하여 사용자의 계좌 정보를 불법적으로 탈취하는 시나리오가 있을 수 있다. SOP는 이러한 접근을 차단한다.

하지만 위에서 설명한 바와 같이, 프론트엔드와 백엔드로 나누어 프로젝트를 진행하게 되면 프론트엔드는 Origin이 다른 백엔드 서버에 리소스를 요청할 수밖에 없다.

위와 같은 상황에서 CORS라는 표준을 통해 타 서버의 리소스를 요청할 수 있도록 한다.

📌 CORS, CORS 에러, SOP 정리

다시 정리하면 아래와 같다.
1. 다른 출처로 리소스를 요청한다면 SOP 정책을 위반한 것이 된다.
2. 출처가 다른 리소스더라도, CORS 정책을 지킨 리소스 요청의 경우 허용된다.
3. 출처도 다르고, CORS 정책도 지키지 않았을 경우 CORS 에러가 발생한다.


4. CORS 에러의 흐름

단순히 CORS 에러의 해결 방법을 알아보기 전에, 문제의 원인을 생각해보자.

프로젝트 중 CORS 문제를 맞닥뜨렸을 때, 다음과 같은 의문이 들지 않았는가?

"Postman으로 백엔드 요청을 테스트할 때는 응답이 잘 가는데, 왜 프론트엔드에서 요청하면 CORS 에러가 발생하는거지?"

아래의 CORS 에러의 흐름을 살펴보자!

위 그림에서 가장 먼저 이해해야 할 점은, CORS 에러는 서버가 아니라 브라우저가 발생시키는 에러라는 점이다.

위의 다이어그램을 보면, 서버 측(localhost:8080)에서는 정상적으로 응답을 줬다는 것을 확인할 수 있다. 즉, 서버는 같은 출처에서 보낸 요청만 받겠다는 특정한 로직을 가지고 있는 경우가 아닌 이상 정상적으로 응답한다.

CORS 에러는 브라우저가 서버 응답의 헤더를 확인한 후, 출처가 다를 경우 발생시킨다. 브라우저는 서버의 응답 중 Access-Control-Allow-OriginAccess-Control-Allow-Methods 헤더를 확인하여 CORS를 검증한다.

여기서 중요한 것은 Access-Control-Allow-Origin로, 이는 리소스를 접근하는 것이 허용된 출처를 의미한다. 브라우저는 자신이 보냈던 요청의 Origin이 서버가 보내준 응답의 Access-Control-Allow-Origin에 포함되어 있는지 확인한 후, 포함되어 있지 않은 경우 CORS 에러를 발생시킨다.

그렇다면 CORS 에러를 해결하는 방법도 감이 올 것이다. 바로 서버 측에서 Access-Control-Allow-Origin에 브라우저의 Origin을 포함시키는 것이다.


5. CORS 에러 해결 방법 (Spring Boot)

서버는 서버의 응답 중 Access-Control-Allow-Origin 헤더를 사용하여 특정 출처 또는 모든 출처 *에서의 요청을 허용할 수 있다.

와일드카드인 *를 사용하여 헤더를 설정하면 모든 출처에서 오는 요청을 허용한다는 의미이다. 이는 간편하지만 신뢰할 수 없는 출처에서 오는 요청까지 모두 허용하는 것으로, 보안상 문제가 발생할 수 있다. 따라서, 신뢰할 수 있는 특정 출처만을 허용하는 것이 바람직하다.

구체적으로, Spring Boot에서 CORS 에러를 해결하기 위한 코드는 아래와 같다.

WebConfig.java

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("OPTIONS","GET","POST","PUT","DELETE");
    }
}

단순히 위와 같이 WebConfig.java를 작성하면 된다.

위의 코드에서는 CorsRegistry 객체를 사용해 모든 경로 "/**"에 대해 모든 출처 "*"와 HTTP 메서드 "OPTIONS", "GET", "POST", "PUT", "DELETE"를 허용하도록 설정되어 있다.

📌 CorsRegistry란?

CorsRegistry는 Spring에서 CORS(Cross-Origin Resource Sharing) 설정을 구성하고 관리하는 클래스이다.


마치며

CORS 에러 해결의 어려운 점은, 에러를 겪는 사람과 에러를 해결해야 하는 사람이 각각 프론트엔드 개발자, 백엔드 개발자로 서로 다르다는 점이다. 백엔드 개발자 입장에서는 Postman으로 테스트를 진행했을 때 정상적으로 응답을 확인할 수 있기 때문에 문제 해결에 난항을 겪을 수 있다. CORS 에러 자체는 해결하기 어려운 문제가 아니므로 CORS에 대한 기본적인 이해를 하고 있는 것이 좋다.

profile
전공/개발 지식 정리

0개의 댓글