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가 브라우저의 정책이기 때문에 당연하겠지만 합리적인 이유에 대해서 찾으면 추가로 포스팅 할 예정이다.