diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index 1e0dc1d8d1cf..5e19d61b2523 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -357,9 +357,19 @@ public static InetSocketAddress parseForwardedFor( String value = matcher.group(1).trim(); String host = value; int portSeparatorIdx = value.lastIndexOf(':'); - if (portSeparatorIdx > value.lastIndexOf(']')) { + int squareBracketIdx = value.lastIndexOf(']'); + if (portSeparatorIdx > squareBracketIdx) { + if (squareBracketIdx == -1 && value.indexOf(':') != portSeparatorIdx) { + throw new IllegalArgumentException("Invalid IPv4 address: " + value); + } host = value.substring(0, portSeparatorIdx); - port = Integer.parseInt(value.substring(portSeparatorIdx + 1)); + try { + port = Integer.parseInt(value.substring(portSeparatorIdx + 1)); + } + catch (NumberFormatException ex) { + throw new IllegalArgumentException( + "Failed to parse a port from \"forwarded\"-type header value: " + value); + } } return new InetSocketAddress(host, port); } @@ -886,7 +896,11 @@ private boolean isForwardedSslOn(HttpHeaders headers) { private void adaptForwardedHost(String rawValue) { int portSeparatorIdx = rawValue.lastIndexOf(':'); - if (portSeparatorIdx > rawValue.lastIndexOf(']')) { + int squareBracketIdx = rawValue.lastIndexOf(']'); + if (portSeparatorIdx > squareBracketIdx) { + if (squareBracketIdx == -1 && rawValue.indexOf(':') != portSeparatorIdx) { + throw new IllegalArgumentException("Invalid IPv4 address: " + rawValue); + } host(rawValue.substring(0, portSeparatorIdx)); port(Integer.parseInt(rawValue.substring(portSeparatorIdx + 1))); } diff --git a/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java b/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java index cd1f6bbad896..c6407c1de3df 100644 --- a/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java +++ b/spring-web/src/test/java/org/springframework/web/filter/ForwardedHeaderFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import org.springframework.web.testfixture.servlet.MockHttpServletResponse; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.Mockito.mock; /** @@ -470,6 +471,13 @@ public void forwardedForMultipleIdentifiers() throws Exception { assertThat(actual.getRemoteAddr()).isEqualTo(actual.getRemoteHost()).isEqualTo("203.0.113.195"); assertThat(actual.getRemotePort()).isEqualTo(MockHttpServletRequest.DEFAULT_SERVER_PORT); } + + @Test // gh-26748 + public void forwardedForInvalidIpV6Address() { + request.addHeader(FORWARDED, "for=\"2a02:918:175:ab60:45ee:c12c:dac1:808b\""); + assertThatIllegalArgumentException().isThrownBy( + ForwardedHeaderFilterTests.this::filterAndGetWrappedRequest); + } } @Nested diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java index 13d9e61b7926..1db9b40628c5 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java @@ -453,6 +453,21 @@ void fromHttpRequestWithForwardedIPv6HostAndPort() { assertThat(result.toString()).isEqualTo("http://[1abc:2abc:3abc::5ABC:6abc]:8080/mvc-showcase"); } + @Test // gh-26748 + void fromHttpRequestWithForwardedInvalidIPv6Address() { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setScheme("http"); + request.setServerName("localhost"); + request.setServerPort(-1); + request.setRequestURI("/mvc-showcase"); + request.addHeader("X-Forwarded-Host", "2a02:918:175:ab60:45ee:c12c:dac1:808b"); + + HttpRequest httpRequest = new ServletServerHttpRequest(request); + + assertThatIllegalArgumentException().isThrownBy(() -> + UriComponentsBuilder.fromHttpRequest(httpRequest).build()); + } + @Test void fromHttpRequestWithForwardedHost() { MockHttpServletRequest request = new MockHttpServletRequest();