- Notifications
You must be signed in to change notification settings - Fork38.6k
Closed
Labels
Milestone
Description
Affects: 6.1.13
if a client sends a malformed origin header in a CORS request to a spring boot application that looks like this:
curl 'http://localhost/sample \ -X 'OPTIONS' \ -H 'Origin: https://*@:;' \
The following exception will be thrown:
j.l.IllegalArgumentException: [https://*@:;] is not a valid HTTP URLat o.s.w.u.UriComponentsBuilder.checkSchemeAndHost(UriComponentsBuilder.java:309)at o.s.w.u.UriComponentsBuilder.fromOriginHeader(UriComponentsBuilder.java:371)at o.s.w.cors.CorsUtils.isCorsRequest(CorsUtils.java:46)at o.s.w.c.DefaultCorsProcessor.processRequest(DefaultCorsProcessor.java:86)
This exception is not handled, and bubbles out as a 500 Internal Server Error.
I would expect that the framework would handle the invalid input and reject the request with a 403 Forbidden with message "invalid cors request", like it does for many other kinds of invalid input.
The only workaround I have found is to register a customcorsFilter
bean, with a customCorsProcessor
that handles the exception and rejects it.
Here's a unit test that fails due to this issue:
package testing;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Test;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpMethod;import org.springframework.http.HttpStatus;import org.springframework.mock.web.MockHttpServletRequest;import org.springframework.mock.web.MockHttpServletResponse;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.CorsProcessor;import org.springframework.web.cors.DefaultCorsProcessor;import java.io.IOException;import static org.junit.jupiter.api.Assertions.assertEquals;import static org.junit.jupiter.api.Assertions.assertFalse;import static org.junit.jupiter.api.Assertions.assertTrue;class SafeCorsProcessorTest { private final CorsConfiguration corsConfiguration = new CorsConfiguration(); private final CorsProcessor processor = new DefaultCorsProcessor(); private final MockHttpServletResponse response = new MockHttpServletResponse(); @BeforeEach void setUp() { response.reset(); } @Test void processRequest() throws IOException { // Given a valid OPTIONS request. var request = new MockHttpServletRequest(); request.addHeader(HttpHeaders.ORIGIN, "http://localhost"); request.setMethod(HttpMethod.OPTIONS.name()); // When processRequest is called var result = processor.processRequest(corsConfiguration, request, response); // Then the result is true and the status code is 200 OK. assertTrue(result); assertEquals(HttpStatus.OK.value(), response.getStatus()); } @Test void processRequestInvalidOrigin() throws IOException { // Given an OPTIONS request with invalid origin header. var request = new MockHttpServletRequest(); request.addHeader(HttpHeaders.ORIGIN, "https://*@:;"); request.setMethod(HttpMethod.OPTIONS.name()); // WHen processRequest is called var result = processor.processRequest(corsConfiguration, request, response); // Then the result is false and status code is 403 Forbidden, assertFalse(result); assertEquals(HttpStatus.FORBIDDEN.value(), response.getStatus()); }}