Post

Spring Boot CORS 오류

1. CORS란

교차 출처 리소스 공유(Cross-origin resource sharing, CORS), 교차 출처 자원 공유는 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다.

CORS는 교차 출처 요청을 허용하는 것이 안전한지 아닌지를 판별하기 위해 브라우저와 서버가 상호 통신하는 하나의 방법을 정의한다. 순수하게 동일한 출처 요청보다 더 많은 자유와 기능을 허용하지만, 단순히 모든 교차 출처 요청을 허용하는 것보다 더 안전하다.

CORS의 사양은 원래 W3C 권고안으로 배포되었으나 해당 문서는 쓸모없어진(obsolete) 상태이다. 현재 CORS를 재정의하면서 활발히 유지보수된 사양은 WHATWG의 Fetch Living Standard이다.

cors-url

2. CORS 동작 원리

cors-operation

3. 해결 방법

1) Configuration 설정

Global하게 적용하는 방법이다.

서버측에서 ACAO 헤더의 값을 와일드카드(*)로 설정하면 출처가 다른 모든 웹 사이트에서 접근할 수 있기 때문에 보안에 취약하다.

1
2
3
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
...
  • WebConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 corsRegistry) {
        corsRegistry.addMapping("/**") // CORS를 적용할 URL패턴 정의
                .allowedOrigins("http://front-server.com") // 자원 공유를 허락할 Origin 지정
                .allowedMethods("GET", "POST") // 허용할 HTTP method 지정
                .maxAge(3000); // 설정 시간만큼 pre-flight 리퀘스트 캐싱
    }
}

2) Annotation 설정

Controller 또는 메소드단에서 annotation을 통해 적용하는 방법이다. origins, methods, maxAge, allowedHeaders를 사용하면 된다.

  • 클래스에 적용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RequiredArgsConstructor
@RestController
@CrossOrigin(origins = "http://front-server.com")
@RequestMapping(path = "/board")
public class Controller {

}
  • 메소드에 적용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping(path = "/board")
public class Controller {

    @CrossOrigin(origins = "http://front-server.com")
    @GetMapping(path = "/{id}")
    public ResponseEntity<String> find(@PathVariable("id") String id) {
        ...
    }

}

[출처 및 참고]

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