[SpringBoot][WebMVC] CORS(Cross-Origin Resource Sharing) 적용

2022. 12. 15. 12:10JAVA/Spring

1. SOP와 CORS란 무엇인가?

SOP(Same-Origin Policy)

동일 출처 정책(SOP, Same-Origin Policy)은 어떤 Origin에서 가져온 리소스와 상호작용하는 것을 제한하는 보안 방식입니다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여줍니다.

 

CORS(Cross-Origin Resource Sharing)

SOP를 우회하기 위한 표준기술입니다. SOP와 CORS 모두 웹 브라우저가 지원하는 기술입니다. SOP는 같은 Origin에만 요청을 보낼 수 있지만 CORS는 서로 다른 Origin끼리 리소스를 공유할 수 있는 기술입니다. 그래서 Cross-Origin 요청을 하기 위해서는 서버의 동의가 필요합니다. 만약 서버가 Cross-Origin 요청을 동의하면 브라우저에서도 요청을 허락하게 되고 서버가 동의하지 않으면 브라우저에서도 거절하게 됩니다.

 

이와 같이 클라이언트와 서버간에 Cross-Origin 요청하고 동의 또는 거절하는 메커니즘을 HTTP-header를 이용해서 가능한데, 이를 CORS(Cross-Origin Resource Sharing)이라고 합니다.

 

Origin

Origin이란 URI 스키마(http, https), hostname(localhost, domain), 포트번호(8080, 18080) 이 3가지를 조합한 형태입니다.

예를 들어 "http://localhost:8080"도 하나의 Origin이고 "http://localhost:18080"도 하나의 Origin입니다.

 

예를 들어 REST API를 제공하는 서버가 "http://localhost:8080"에서 제공하고 있고 해당 서버에 "http://localhost:18080"을 사용하는 애플리케이션이 호출한다면 기본적으로 SOP에 의해서 거부될 것입니다. 이렇게 다른 Origin에서 자원이 있는 Origin에 자원 공유를 요청하게 할 수 있는 기술이 CORS입니다.

 

2. SpringBoot에서 CORS

CORS 기술은 Spring MVC에서 지원하고 SpringBoot에서는 별다른 빈 설정없이 @CrossOrigin 애노테이션을 이용하면 손쉽게 CORS 기술을 사용할 수 있습니다.

 

2.1 CORS 적용 방법 1 : 컨트롤러 내 매핑 메서드에 적용

@CrossOrigin(origins = {"http://localhost:18080"})
@GetMapping("/hello")
public String hello(){
    return "hello";
}

 

2.2 CORS 적용 방법 2 : 컨트롤러 내 전체 매핑 메서드에 적용

@RestController
@CrossOrigin(origins = {"http://localhost:18080"})
@RequestMapping("/sample")
public class SampleController {
    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }
}

 

2.3 CORS 적용 방법 3 : 웹 설정 클래스를 생성하여 WebMvcConfigurer 인터페이스의 addCorsMappings 메서드를 구현하여 적용

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/sample/hello")
                .allowedOrigins("http://localhost:18080/");
    }
}

 

3. SpringBoot에서 CORS 적용 실습

 

1. 서버 프로젝트 의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-web'

 

2. 서버 REST API 구현

방법1 : 특정 컨트롤러 메서드 또는 컨트롤러 전체에 CORS 적용

@RestController
//@CrossOrigin(origins = {"<http://localhost:18080>"}) // 해당 컨트롤러 내에 메서드 전체에 적용
@RequestMapping("/sample")
public class SampleController {
    @CrossOrigin(origins = {"<http://localhost:18080>"})
    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }
}

 

방법2 : 웹 설정 클래스 파일을 생성하고 WebMvcConfigurer 인터페이스의 addCorsMappings 메서드를 구현

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/sample/hello")
                .allowedOrigins("<http://localhost:18080/>");
    }
}

 

3. 클라이언트 프로젝트 의존성추가

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.webjars.bower:jquery:3.6.1

 

4. 클라이언트 프로젝트 포트 설정

resources/application.properties

server.port=18080

 

5. 클라이언트의 페이지 작성

resources/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>hello world</h1>

    <script src="webjars/jquery/3.6.1/dist/jquery.min.js"></script>
    <script>
        $(function(){
           $.ajax("<http://localhost:8080/sample/hello>")
               .done(function(msg){
                  alert(msg);
               })
               .fail(function(){
                  alert("fail");
               });
        });
    </script>
</body>
</html>

페이지가 로드되자마자 서버 프로젝트에 있는 “http://localhost:8080/sample/hello” url을 요청하여 “hello”라는 문자열 리소스를 받아옵니다. 만약 이 접근이 실패하면 fail을 알립니다.

 

6. 서버와 클라이언트 프로젝트를 실행하고 브라우저에 “http://localhost:18080/”을 요청하여 알림문으로 “hello”가 출력되는지 확인합니다.

 

References

source code : https://github.com/yonghwankim-dev/springboot_practice/tree/main/cors_demo/src/main/java/com
https://hannut91.github.io/blogs/infra/cors
[인프런] 스프링부트 개념과 활용