Skip to content

Commit

Permalink
Reject CORS request with 403 if Origin header is malformed
Browse files Browse the repository at this point in the history
When assessing if a request is a CORS request, both mvc and reactive
`DefaultCorsProcessor` now catch `IllegalArgumentException` and turn
this into a 403 rejection rather than letting the exception propagate
into a 500 response.

Closes gh-33688
  • Loading branch information
simonbasle committed Oct 14, 2024
1 parent f991c19 commit 8da31e1
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,15 @@ public boolean processRequest(@Nullable CorsConfiguration config, HttpServletReq
response.addHeader(HttpHeaders.VARY, HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
}

if (!CorsUtils.isCorsRequest(request)) {
return true;
try {
if (!CorsUtils.isCorsRequest(request)) {
return true;
}
}
catch (IllegalArgumentException ex) {
logger.debug("Reject: origin is malformed");
rejectRequest(new ServletServerHttpResponse(response));
return false;
}

if (response.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,15 @@ public boolean process(@Nullable CorsConfiguration config, ServerWebExchange exc
}
}

if (!CorsUtils.isCorsRequest(request)) {
return true;
try {
if (!CorsUtils.isCorsRequest(request)) {
return true;
}
}
catch (IllegalArgumentException ex) {
logger.debug("Reject: origin is malformed");
rejectRequest(response);
return false;
}

if (responseHeaders.getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,20 @@ public void actualRequestTrailingSlashOriginMatch() throws Exception {
assertThat(this.response.containsHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
}

@Test //gh-33682
public void actualRequestMalformedOriginRejected() throws Exception {
this.request.setMethod(HttpMethod.GET.name());
this.request.addHeader(HttpHeaders.ORIGIN, "http://*@:;");
this.conf.addAllowedOrigin("https://domain2.com");

boolean result = this.processor.processRequest(this.conf, this.request, this.response);
assertThat(result).isFalse();
assertThat(this.response.containsHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
assertThat(this.response.getHeaders(HttpHeaders.VARY)).contains(HttpHeaders.ORIGIN,
HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}

@Test
void actualRequestExposedHeaders() throws Exception {
this.request.setMethod(HttpMethod.GET.name());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,21 @@ public void actualRequestTrailingSlashOriginMatch() {
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isTrue();
}

@Test // gh-33682
public void actualRequestMalformedOriginRejected() {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest
.method(HttpMethod.GET, "http://localhost/test.html")
.header(HttpHeaders.ORIGIN, "http://*@:;"));

this.conf.addAllowedOrigin("https://domain2.com");
boolean result = this.processor.process(this.conf, exchange);
ServerHttpResponse response = exchange.getResponse();

assertThat(result).isFalse();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
assertThat(response.getHeaders().containsKey(ACCESS_CONTROL_ALLOW_ORIGIN)).isFalse();
}

@Test
void actualRequestExposedHeaders() {
ServerWebExchange exchange = actualRequest();
Expand Down

0 comments on commit 8da31e1

Please sign in to comment.