CORS란?

웹 개발을 하다 보면 한 번쯤은 부딪히게 되는 주제가 CORS이다. 이 포스팅에서는 CORS가 무엇이며 CORS 예외를 어떻게 해결해야 하는지 알아보자.
배경 및 정의
기존 브라우저 정책은 서로 다른 도메인으로부터 리소스가 필요한 경우, 보안상의 이유로 다른 도메인의 리소스를 가져오는 것이 불가능했다. (SOP : Single-Origin-Policy) 하지만 어플리케이션을 개선하고 쉽게 개발하기 위해선 다른 도메인에 요청을 보내는 일은 필연적이다. 이를 해결하고자 등장한 표준 기술이 CORS이다.
CORS란 Cross Origin Resource Sharing 의 약자로 도메인이 다른 자원에 리소스를 요청할 때 접근 권한을 부여하는 메커니즘이다. 쉽게 말하자면 친구의 물건을 쓰려면 친구가 제한하는 규약안에서 사용해야 하듯, 다른 도메인의 자원을 쓰려면 자원의 주인이 허락한 규약을 지켜야 하는 것이고 이러한 규약을 표준화한 것이 CORS 이다.
- 여기서 말하는 도메인이란 Resource를 의미하며 프로토콜, 호스트, 포트를 의미한다. (ex. http : 프로토콜, localhost : 호스트, 8080: 포트)
CORS가 발생하는 예시
Client와 Server라는 스프링부트 프로젝트를 시작하고, Client에서 Server로 fetch 요청을 쏘는 예제를 생각해보자.
- Server Code
@RestController
public class ServerSideController {
@GetMapping("/server")
public String message() {
return "server";
}
}서버에서는 단순히 String 을 리턴하는 RestController 를 하나 만들어준다.
- Client Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Client - Server</title>
</head>
<body>
<script>
fetch('http://localhost:8080/server').then(response => {
alert(response);
});
</script>
</body>
</html>클라이언트 쪽에서는 단순히 index.html 에서 서버로 요청을 쏘도록 설정하였다. 주의할 점은 CORS는 클라이언트가 다른 도메인으로 요청을 보내야 하기 때문에, 서로 다른 포트를 설정하였다(서버는 8080, 클라이언트는 7070으로 설정하였다.)
위와 같이 설정하고 [http://localhost:7070/](http://localhost:7070/) 으로 접근하면 아래와 같은 CORS 예외가 발생한다. 이는 클라이언트는 http://localhost:7070 도메인을 사용하고 서버는 [http://localhost:8080](http://localhost:8080) 을 사용하고 있기 때문에, 다른 도메인에 접근하지 못하도록(프로토콜과 호스트는 같지만, 포트가 다르기 때문에) 예외를 발생시키는 것이다.

해결책
가장 단순한 해결책은 @CrossOrigin 을 사용하는 것이다. 아래와 같이 @CrossOrigin 을 사용하면 다른 도메인의 클라이언트가 나의 서버에 요청 보내는 것을 허용하는 것이다.
@RestController
public class ServerSideController {
@CrossOrigin("http://localhost:7070")
@GetMapping("/server")
public String message() {
return "server";
}
}세부적으로 자신의 서버에서 CrossOrigin 을 설정하고 싶다면 아래의 방법과 같이 Configuration 을 추가하는 방법도 있다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}PS
처음 CORS를 접했을 때 의문은 왜 서버는 되는데 브라우저에서만, 다른 도메인으로의 요청이 막혀있지?
였다. 애초에 Single Origin Policy가 브라우저의 정책이기 때문에 당연하겠지만 합리적인 이유에 대해서 찾으면 추가로 포스팅 할 예정이다.
