diff --git a/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java b/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java index f120b25976c..6a875ce0591 100644 --- a/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java +++ b/spring-web/src/main/java/org/springframework/web/filter/ForwardedHeaderFilter.java @@ -97,7 +97,7 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { } - private final boolean useStandardHeader; + private final @Nullable Boolean useStandardHeader; private boolean useForwardedPrefix; @@ -106,6 +106,22 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { private boolean relativeRedirects; + /** + * A default constructor with the historic behavior so far, which is to check + * both the standard "Forwarded" header and the "X-Forwarded-*" alternative + * headers in that order, also with "X-Forwarded-Prefix" enabled by default. + *

This behavior depends on proxies being configured correctly + * to clear both standard "Forwarded" and "X-Forwarded-*" header values coming + * from the outside. Going forward, applications must explicitly declare which + * forwarded headers are expected. + * @deprecated as of 7.1, in favor of {@link #ForwardedHeaderFilter(boolean)} + */ + @Deprecated(since = "7.1", forRemoval = true) + public ForwardedHeaderFilter() { + this.useStandardHeader = null; + this.useForwardedPrefix = true; + } + /** * Create an instance of the filter and specify whether it should use the * standard "Forwarded" header or the "X-Forwarded-*" alternative headers. @@ -220,6 +236,24 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { doFilterInternal(request, response, filterChain); } + @SuppressWarnings("removal") + private static ForwardedHeaderUtils.ForwardedInfo getForwardedInfo( + @Nullable Boolean useStandardHeader, URI uri, HttpHeaders headers, + @Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress) { + + if (useStandardHeader == null) { + return new ForwardedHeaderUtils.ForwardedInfo( + ForwardedHeaderUtils.adaptFromForwardedHeaders(uri, headers), + ForwardedHeaderUtils.parseForwardedFor(uri, headers, remoteAddress), + ForwardedHeaderUtils.parseForwardedBy(uri, headers, localAddress)); + } + else { + return (useStandardHeader ? + ForwardedHeaderUtils.parseStandardHeader(uri, headers, remoteAddress, localAddress) : + ForwardedHeaderUtils.parseXForwardedHeaders(uri, headers, remoteAddress, localAddress)); + } + } + /** * Hide "Forwarded" or "X-Forwarded-*" headers. @@ -290,19 +324,15 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { private final ForwardedPrefixExtractor forwardedPrefixExtractor; ForwardedHeaderExtractingRequest( - HttpServletRequest servletRequest, boolean useStandardHeader, boolean useForwardedPrefix) { + HttpServletRequest servletRequest, @Nullable Boolean useStandardHeader, boolean useForwardedPrefix) { super(servletRequest); ServerHttpRequest request = new ServletServerHttpRequest(servletRequest); - URI uri = request.getURI(); - HttpHeaders headers = request.getHeaders(); - InetSocketAddress remoteAddress = request.getRemoteAddress(); - InetSocketAddress localAddress = request.getLocalAddress(); - ForwardedHeaderUtils.ForwardedInfo info = (useStandardHeader ? - ForwardedHeaderUtils.parseStandardHeader(uri, headers, remoteAddress, localAddress) : - ForwardedHeaderUtils.parseXForwardedHeaders(uri, headers, remoteAddress, localAddress)); + ForwardedHeaderUtils.ForwardedInfo info = getForwardedInfo( + useStandardHeader, request.getURI(), request.getHeaders(), + request.getRemoteAddress(), request.getLocalAddress()); UriComponents uriComponents = info.uriComponentsBuilder().build(); int port = uriComponents.getPort(); @@ -516,10 +546,10 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { private final HttpServletRequest request; - private final boolean useStandardHeader; + private final @Nullable Boolean useStandardHeader; ForwardedHeaderExtractingResponse( - HttpServletResponse response, HttpServletRequest request, boolean useStandardHeader) { + HttpServletResponse response, HttpServletRequest request, @Nullable Boolean useStandardHeader) { super(response); this.request = request; @@ -555,9 +585,8 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter { URI uri = httpRequest.getURI(); HttpHeaders headers = httpRequest.getHeaders(); - ForwardedHeaderUtils.ForwardedInfo info = (this.useStandardHeader ? - ForwardedHeaderUtils.parseStandardHeader(uri, headers, null, null) : - ForwardedHeaderUtils.parseXForwardedHeaders(uri, headers, null, null)); + ForwardedHeaderUtils.ForwardedInfo info = + getForwardedInfo(this.useStandardHeader, uri, headers, null, null); String result = info.uriComponentsBuilder() .replacePath(path) diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java b/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java index 99fcba8c0f5..443b87ea502 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/ForwardedHeaderTransformer.java @@ -83,13 +83,29 @@ public class ForwardedHeaderTransformer implements FunctionThis behavior depends on proxies being configured correctly + * to clear both standard "Forwarded" and "X-Forwarded-*" header values coming + * from the outside. Going forward, applications must explicitly declare which + * forwarded headers are expected. + * @deprecated as of 7.1, in favor of {@link #ForwardedHeaderTransformer(boolean)} + */ + @Deprecated(since = "7.1", forRemoval = true) + public ForwardedHeaderTransformer() { + this.useStandardHeader = null; + this.useForwardedPrefix = true; + } + /** * Create an instance of the transformer and specify whether it should use the * standard "Forwarded" header or the "X-Forwarded-*" alternative headers. @@ -146,9 +162,8 @@ public class ForwardedHeaderTransformer implements Function FORWARDED_HEADER_NAMES.forEach(map::remove)); } diff --git a/spring-web/src/main/java/org/springframework/web/util/ForwardedHeaderUtils.java b/spring-web/src/main/java/org/springframework/web/util/ForwardedHeaderUtils.java index 6f7dec88bf0..4e868e8c0fe 100644 --- a/spring-web/src/main/java/org/springframework/web/util/ForwardedHeaderUtils.java +++ b/spring-web/src/main/java/org/springframework/web/util/ForwardedHeaderUtils.java @@ -314,7 +314,10 @@ public abstract class ForwardedHeaderUtils { * @param headers the HTTP headers to consider * @return a {@link UriComponentsBuilder} that reflects the request URI and * additional updates from forwarded headers + * @deprecated as of 7.1 in favor of {@link #parseStandardHeader} and + * {@link #parseXForwardedHeaders} */ + @Deprecated(since = "7.1", forRemoval = true) public static UriComponentsBuilder adaptFromForwardedHeaders(URI uri, HttpHeaders headers) { UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(uri); try { @@ -373,8 +376,10 @@ public abstract class ForwardedHeaderUtils { * @param remoteAddress the current remote address * @return an {@code InetSocketAddress} with the extracted host and port, or * {@code null} if the headers are not present - * @see RFC 7239, Section 5.2 + * @deprecated as of 7.1 in favor of {@link #parseStandardHeader} and + * {@link #parseXForwardedHeaders} */ + @Deprecated(since = "7.1", forRemoval = true) public static @Nullable InetSocketAddress parseForwardedFor( URI uri, HttpHeaders headers, @Nullable InetSocketAddress remoteAddress) { @@ -408,8 +413,10 @@ public abstract class ForwardedHeaderUtils { * @return an {@code InetSocketAddress} with the extracted host and port, or * {@code null} if the headers are not present * @since 7.0 - * @see RFC 7239, Section 5.1 + * @deprecated as of 7.1 in favor of {@link #parseStandardHeader} and + * {@link #parseXForwardedHeaders} */ + @Deprecated(since = "7.1", forRemoval = true) public static @Nullable InetSocketAddress parseForwardedBy( URI uri, HttpHeaders headers, @Nullable InetSocketAddress localAddress) {