Skip to content

Commit 4c5cbc8

Browse files
github-actions[bot]Yannic Hamann
andauthored
[release/8.0] Forwarded Headers Middleware: Ignore XForwardedHeaders from Unknown Proxy (#61623)
* Header Spoofing Proof for XForwardedProto, XForwardedHost and XForwardedPrefix * Fix Header Spoofing --------- Co-authored-by: Yannic Hamann <yannic.hamann@th.abb.com>
1 parent 1bc29c1 commit 4c5cbc8

File tree

2 files changed

+82
-9
lines changed

2 files changed

+82
-9
lines changed

src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -228,19 +228,19 @@ public void ApplyForwarders(HttpContext context)
228228
for (; entriesConsumed < sets.Length; entriesConsumed++)
229229
{
230230
var set = sets[entriesConsumed];
231-
if (checkFor)
231+
// For the first instance, allow remoteIp to be null for servers that don't support it natively.
232+
if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address))
232233
{
233-
// For the first instance, allow remoteIp to be null for servers that don't support it natively.
234-
if (currentValues.RemoteIpAndPort != null && checkKnownIps && !CheckKnownAddress(currentValues.RemoteIpAndPort.Address))
234+
// Stop at the first unknown remote IP, but still apply changes processed so far.
235+
if (_logger.IsEnabled(LogLevel.Debug))
235236
{
236-
// Stop at the first unknown remote IP, but still apply changes processed so far.
237-
if (_logger.IsEnabled(LogLevel.Debug))
238-
{
239-
_logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort);
240-
}
241-
break;
237+
_logger.LogDebug(1, "Unknown proxy: {RemoteIpAndPort}", currentValues.RemoteIpAndPort);
242238
}
239+
break;
240+
}
243241

242+
if (checkFor)
243+
{
244244
if (IPEndPoint.TryParse(set.IpAndPortText, out var parsedEndPoint))
245245
{
246246
applyChanges = true;

src/Middleware/HttpOverrides/test/ForwardedHeadersMiddlewareTest.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,79 @@ public async Task AllOptionsDisabledRequestDoesntChange()
962962
Assert.Equal(PathString.Empty, context.Request.PathBase);
963963
}
964964

965+
[Theory]
966+
[InlineData(ForwardedHeaders.XForwardedFor, false)]
967+
[InlineData(ForwardedHeaders.XForwardedFor, true)]
968+
[InlineData(ForwardedHeaders.XForwardedHost, false)]
969+
[InlineData(ForwardedHeaders.XForwardedHost, true)]
970+
[InlineData(ForwardedHeaders.XForwardedProto, false)]
971+
[InlineData(ForwardedHeaders.XForwardedProto, true)]
972+
[InlineData(ForwardedHeaders.XForwardedPrefix, false)]
973+
[InlineData(ForwardedHeaders.XForwardedPrefix, true)]
974+
public async Task IgnoreXForwardedHeadersFromUnknownProxy(ForwardedHeaders forwardedHeaders, bool unknownProxy)
975+
{
976+
using var host = new HostBuilder()
977+
.ConfigureWebHost(webHostBuilder =>
978+
{
979+
webHostBuilder
980+
.UseTestServer()
981+
.Configure(app =>
982+
{
983+
var options = new ForwardedHeadersOptions
984+
{
985+
ForwardedHeaders = forwardedHeaders
986+
};
987+
if (!unknownProxy)
988+
{
989+
var proxy = IPAddress.Parse("10.0.0.1");
990+
options.KnownProxies.Add(proxy);
991+
}
992+
app.UseForwardedHeaders(options);
993+
});
994+
}).Build();
995+
996+
await host.StartAsync();
997+
998+
var server = host.GetTestServer();
999+
1000+
var context = await server.SendAsync(c =>
1001+
{
1002+
c.Request.Headers["X-Forwarded-For"] = "11.111.111.11";
1003+
c.Request.Headers["X-Forwarded-Host"] = "testhost";
1004+
c.Request.Headers["X-Forwarded-Proto"] = "Protocol";
1005+
c.Request.Headers["X-Forwarded-Prefix"] = "/pathbase";
1006+
c.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1");
1007+
c.Connection.RemotePort = 99;
1008+
});
1009+
1010+
if (unknownProxy)
1011+
{
1012+
Assert.Equal("10.0.0.1", context.Connection.RemoteIpAddress.ToString());
1013+
Assert.Equal("localhost", context.Request.Host.ToString());
1014+
Assert.Equal("http", context.Request.Scheme);
1015+
Assert.Equal(PathString.Empty, context.Request.PathBase);
1016+
}
1017+
else
1018+
{
1019+
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedFor))
1020+
{
1021+
Assert.Equal("11.111.111.11", context.Connection.RemoteIpAddress.ToString());
1022+
}
1023+
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedHost))
1024+
{
1025+
Assert.Equal("testhost", context.Request.Host.ToString());
1026+
}
1027+
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedProto))
1028+
{
1029+
Assert.Equal("Protocol", context.Request.Scheme);
1030+
}
1031+
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedPrefix))
1032+
{
1033+
Assert.Equal("/pathbase", context.Request.PathBase);
1034+
}
1035+
}
1036+
}
1037+
9651038
[Fact]
9661039
public async Task PartiallyEnabledForwardsPartiallyChangesRequest()
9671040
{

0 commit comments

Comments
 (0)