This is an automated email from the ASF dual-hosted git repository.

dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new fef9dd0c7c fix: validate forwarded remote addresses before resolution 
(#7065)
fef9dd0c7c is described below

commit fef9dd0c7c8279be3e5bfcc0d2cd62da777f1dee
Author: Southern <[email protected]>
AuthorDate: Fri Sep 18 14:03:03 2026 +0800

    fix: validate forwarded remote addresses before resolution (#7065)
    
    - Preserve valid single-value X-Forwarded-For headers and discard empty 
values.
      - Parse only literal IPv4 and IPv6 addresses to prevent blocking DNS 
lookups.
      - Fall back to the TCP remote address when the forwarded value is invalid.
      - Add regression tests for valid, empty, invalid, IPv6, and multi-value 
headers.
    
    Co-authored-by: zhengpeng <[email protected]>
    Co-authored-by: Liming Deng <[email protected]>
---
 .../forward/ForwardedRemoteAddressResolver.java    |  9 ++++++--
 .../ForwardedRemoteAddressResolverTest.java        | 27 ++++++++++++++++++----
 2 files changed, 29 insertions(+), 7 deletions(-)

diff --git 
a/shenyu-web/src/main/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolver.java
 
b/shenyu-web/src/main/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolver.java
index 0c84a7f064..72690e6bfd 100644
--- 
a/shenyu-web/src/main/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolver.java
+++ 
b/shenyu-web/src/main/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolver.java
@@ -17,6 +17,7 @@
 
 package org.apache.shenyu.web.forward;
 
+import com.google.common.net.InetAddresses;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.plugin.api.RemoteAddressResolver;
@@ -87,7 +88,11 @@ public class ForwardedRemoteAddressResolver implements 
RemoteAddressResolver {
         List<String> xForwardedValues = extractXForwardedValues(exchange);
         if (CollectionUtils.isNotEmpty(xForwardedValues)) {
             int index = Math.min(xForwardedValues.size(), maxTrustedIndex) - 1;
-            return new InetSocketAddress(xForwardedValues.get(index), 0);
+            try {
+                return new 
InetSocketAddress(InetAddresses.forString(xForwardedValues.get(index)), 0);
+            } catch (IllegalArgumentException ex) {
+                LOG.warn("Invalid IP address in X-Forwarded-For header, 
falling back to remote address");
+            }
         }
         return defaultRemoteIpResolver.resolve(exchange);
     }
@@ -103,7 +108,7 @@ public class ForwardedRemoteAddressResolver implements 
RemoteAddressResolver {
             return Collections.emptyList();
         }
         List<String> values = Arrays.asList(xForwardedValues.get(0).split(", 
"));
-        if (values.size() == 1 && StringUtils.isNotEmpty(values.get(0))) {
+        if (values.size() == 1 && StringUtils.isEmpty(values.get(0))) {
             return Collections.emptyList();
         }
         return values;
diff --git 
a/shenyu-web/src/test/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolverTest.java
 
b/shenyu-web/src/test/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolverTest.java
index d790d67128..5ca21932ab 100644
--- 
a/shenyu-web/src/test/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolverTest.java
+++ 
b/shenyu-web/src/test/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolverTest.java
@@ -27,6 +27,7 @@ import 
org.springframework.mock.web.server.MockServerWebExchange;
 import org.springframework.test.util.ReflectionTestUtils;
 import org.springframework.web.server.ServerWebExchange;
 
+import java.net.InetSocketAddress;
 import java.util.Collections;
 
 import static 
org.apache.shenyu.web.forward.ForwardedRemoteAddressResolver.X_FORWARDED_FOR;
@@ -61,26 +62,42 @@ public final class ForwardedRemoteAddressResolverTest {
     @Test
     public void testResolver() {
         ForwardedRemoteAddressResolver instance = 
ForwardedRemoteAddressResolver.maxTrustedIndex(1);
+        InetSocketAddress remoteAddress = new InetSocketAddress("192.0.2.10", 
8080);
         final ServerWebExchange exchange = 
MockServerWebExchange.from(MockServerHttpRequest.post("localhost")
+                .remoteAddress(remoteAddress)
                 .build());
         final ServerWebExchange emptyForwardExchange = 
MockServerWebExchange.from(MockServerHttpRequest.post("localhost")
                 .header("X-Forwarded-For", "")
+                .remoteAddress(remoteAddress)
                 .build());
         final ServerWebExchange forwardExchange = 
MockServerWebExchange.from(MockServerHttpRequest.post("localhost")
                 .header("X-Forwarded-For", "127.0.0.1")
+                .remoteAddress(remoteAddress)
                 .build());
         final ServerWebExchange multiForwardExchangeError = 
MockServerWebExchange.from(MockServerHttpRequest.post("localhost")
                 .header("X-Forwarded-For", "127.0.0.1", "127.0.0.2")
+                .remoteAddress(remoteAddress)
                 .build());
         final ServerWebExchange multiForwardExchange = 
MockServerWebExchange.from(MockServerHttpRequest.post("localhost")
                 .header("X-Forwarded-For", "127.0.0.1, 127.0.0.2")
+                .remoteAddress(remoteAddress)
+                .build());
+        final ServerWebExchange ipv6ForwardExchange = 
MockServerWebExchange.from(MockServerHttpRequest.post("localhost")
+                .header("X-Forwarded-For", "2001:db8::1")
+                .remoteAddress(remoteAddress)
+                .build());
+        final ServerWebExchange hostnameForwardExchange = 
MockServerWebExchange.from(MockServerHttpRequest.post("localhost")
+                .header("X-Forwarded-For", "attacker.example")
+                .remoteAddress(remoteAddress)
                 .build());
 
-        instance.resolve(exchange);
-        instance.resolve(emptyForwardExchange);
-        instance.resolve(forwardExchange);
-        instance.resolve(multiForwardExchangeError);
-        instance.resolve(multiForwardExchange);
+        assertEquals(remoteAddress, instance.resolve(exchange));
+        assertEquals(remoteAddress, instance.resolve(emptyForwardExchange));
+        assertEquals("127.0.0.1", 
instance.resolve(forwardExchange).getAddress().getHostAddress());
+        assertEquals(remoteAddress, 
instance.resolve(multiForwardExchangeError));
+        assertEquals("127.0.0.1", 
instance.resolve(multiForwardExchange).getAddress().getHostAddress());
+        assertEquals("2001:db8:0:0:0:0:0:1", 
instance.resolve(ipv6ForwardExchange).getAddress().getHostAddress());
+        assertEquals(remoteAddress, instance.resolve(hostnameForwardExchange));
 
         ServerWebExchange headerEmptyExchange = mock(ServerWebExchange.class);
         ServerHttpRequest headerEmptyServerHttpRequest = 
mock(ServerHttpRequest.class);

Reply via email to