Aias00 opened a new issue, #6823:
URL: https://github.com/apache/shenyu/issues/6823
## Description
`ForwardedRemoteAddressResolver` (the production default, wired as `new
ForwardedRemoteAddressResolver(1)` in `ShenyuConfiguration`) has an inverted
guard in `extractXForwardedValues`: after splitting `X-Forwarded-For` by `",
"`, it does
```java
if (values.size() == 1 && StringUtils.isNotEmpty(values.get(0))) {
return Collections.emptyList();
}
```
`isNotEmpty` is the opposite of the intended check. The intent is to discard
a single *empty* value (blank header), but the code discards a single
*non-empty* value — i.e. a valid single client IP. `resolve()` then falls
through to the TCP peer address (the proxy's IP), discarding the real client
IP. Conversely, an empty-value header is *not* discarded and produces `new
InetSocketAddress("", 0)` → wildcard `0.0.0.0`.
Additionally `resolve()` constructs `new
InetSocketAddress(xForwardedValues.get(index), 0)`; the
`InetSocketAddress(String,int)` ctor performs a **blocking DNS lookup** when
the value is not a literal IP. `X-Forwarded-For` is unvalidated client input;
with the default `maxTrustedIndex=1` the leftmost (most spoofable) value is
selected. When `shenyu.scheduler.enabled=false` (default),
`HostAddressUtils.acquireIp` runs on the Netty event loop → blocking DNS stalls
all connections on that thread (DoS) and enables DNS
exfiltration/reconnaissance.
## Location
-
`shenyu-web/src/main/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolver.java:89-108`
(inverted guard :106-108; blocking DNS :89-90)
-
`shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java:158-160`
(production default)
## Impact
- Default deployment (single-hop trusted proxy appending one client IP — the
most common case) silently ignores the client IP.
`HostAddressUtils.acquireIp(exchange)` (consumed by `AbstractLoggingPlugin` for
`clientIp`, and by any IP-based allow/deny/rate-limit feature) returns the
proxy's IP. Access logs, rate limiting, and IP-based security all see the wrong
IP.
- DoS: crafted `X-Forwarded-For` hostnames trigger blocking DNS (up to
system DNS timeout, 5–15s) on the event loop.
- DNS exfiltration: gateway resolves attacker-controlled hostnames, leaking
data to attacker's DNS server.
## Suggested fix
- Change `StringUtils.isNotEmpty(values.get(0))` →
`StringUtils.isEmpty(values.get(0))` so only empty single values are discarded.
- Validate the selected value is a literal IP
(`InetAddressUtils.isIPv4/IPv6` or try `InetAddress.getByAddress`) before
constructing `InetSocketAddress`; otherwise fall back to the TCP remote
address. Never call `new InetSocketAddress(String,int)` with unvalidated input
on a reactive thread.
## Related existing
None. Distinct from #6556 (WebSocket Upgrade header case-sensitivity in
`DefaultShenyuContextBuilder`).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]