Spring Backend에 Vue Frontend를 구성해 테스트를 하던 중 POST 요청은 정상적으로 동작하는데 PUT 요청 시 403 에러가 발생하는 상황을 만났습니다.
> OPTIONS http://localhost:8080/api/post/10 403
> Access to XMLHttpRequest at 'http://localhost:8080/api/post/10' from origin 'http://localhost:8081' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
에러 메시지와 요청을 살펴보니 PUT 요청 전 preflight 요청인 OPTIONS 에서 403 에러가 발생했는데 이미 Spring Security 설정에서 Frontend의 CORS와 모든 preflight 요청은 허용한 상태였습니다.
WebMvcConfigurer
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://frontend.domain");
}
WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
...
}
원인을 찾아보기 위해 CORS 설정을 추가한 CorsRegistry의 내용을 확인해 보았습니다.
public class CorsRegistry {
private final List<CorsRegistration> registrations = new ArrayList<>();
...
protected Map<String, CorsConfiguration> getCorsConfigurations() {
Map<String, CorsConfiguration> configs = new LinkedHashMap<>(this.registrations.size());
for (CorsRegistration registration : this.registrations) {
configs.put(registration.getPathPattern(), registration.getCorsConfiguration());
}
return configs;
}
}
getCorsConfigurations() 를 보니 입력받은 설정값을 CorsConfiguration 객체에 넣어주고 있습니다. 따라서 CorsConfiguration 클래스를 확인해봅니다. 위 설정에 따라 실행하면 아래 applyPermitDefaultValues() 메소드가 호출됩니다.
public class CorsConfiguration {
...
private static final List<String> DEFAULT_PERMIT_METHODS = Collections.unmodifiableList(
Arrays.asList(HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name()));
...
public CorsConfiguration applyPermitDefaultValues() {
...
if (this.allowedMethods == null) {
this.allowedMethods = DEFAULT_PERMIT_METHODS;
this.resolvedMethods = DEFAULT_PERMIT_METHODS
.stream().map(HttpMethod::resolve).collect(Collectors.toList());
}
...
return this;
}
}
applyPermitDefaultValues() 메소드를 보면 allowMethods 설정을 하지 않을 경우 GET,HEAD,POST Method를 기본값으로 추가하고 있습니다. 이때 PUT Method가 포함되지 않기 때문에 403 에러가 발생한 것입니다.
따라서 아래와 같이 허용할 설정해 주면 해결할 수 있는데 allowMethod를 추가할 경우 DEFAULT 설정이 사라지기 때문에 GET,HEAD,POST 또한 포함해 주어야 합니다.
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowedMethods(
HttpMethod.GET.name(),
HttpMethod.HEAD.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name());
}
안녕하세요. 허용 Method 설정 관련해서 물어보고 싶은게 있습니다.
GET, POST, PUT, DELETE 을 사용하게 설정 해놨습니다.
OPTIONS 를 호출 시 403 에러가 나면서 response headers 값에
Allow : GET, POST, PUT, DELETE, TRACE, OPTIONS, PATCH 이렇게 나오는데,
보안상 문제가 될까요?