From b476d21bfdac89c25e4bd80869dc78a8efdec229 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Thu, 10 Apr 2025 04:50:08 +0000 Subject: [PATCH 01/10] feat: support ForwardedHeaders configuration --- .../src/ForwardedHeadersOptionsSetup.cs | 19 ++++++++++- .../WebHostTests.cs | 32 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs index 98835ff05482..f55019e9f115 100644 --- a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs +++ b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs @@ -24,7 +24,24 @@ public void Configure(ForwardedHeadersOptions options) return; } - options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + var forwardedHeaders = _configuration["ForwardedHeaders_Headers"]; + if (string.IsNullOrEmpty(forwardedHeaders)) + { + options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + } + else + { + var headers = ForwardedHeaders.None; + foreach (var headerName in forwardedHeaders.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) + { + if (Enum.TryParse(headerName, true, out var headerValue)) + { + headers |= headerValue; + } + } + options.ForwardedHeaders = headers; + } + // Only loopback proxies are allowed by default. Clear that restriction because forwarders are // being enabled by explicit configuration. options.KnownNetworks.Clear(); diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs index 8205e1459a08..4f93c6f4050d 100644 --- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs +++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs @@ -83,6 +83,38 @@ public async Task WebHostConfiguration_EnablesForwardedHeadersFromConfig() result.EnsureSuccessStatusCode(); } + [Fact] + public async Task WebHostConfiguration_EnablesForwardedHeaders_CustomHeaders_FromConfig() + { + using var host = WebHost.CreateDefaultBuilder() + .ConfigureAppConfiguration(configBuilder => + { + configBuilder.AddInMemoryCollection(new[] + { + new KeyValuePair("FORWARDEDHEADERS_ENABLED", "true" ), + new KeyValuePair("FORWARDEDHEADERS_HEADERS", "All" ), + }); + }) + .UseTestServer() + .Configure(app => + { + Assert.True(app.Properties.ContainsKey("ForwardedHeadersAdded"), "Forwarded Headers"); + app.Run(context => + { + Assert.Equal("https", context.Request.Scheme); + Assert.Equal("/test", context.Request.PathBase.Value); + return Task.CompletedTask; + }); + }).Build(); + + await host.StartAsync(); + var client = host.GetTestClient(); + client.DefaultRequestHeaders.Add("x-forwarded-proto", "https"); + client.DefaultRequestHeaders.Add("x-forwarded-prefix", "/test"); + var result = await client.GetAsync("http://localhost/"); + result.EnsureSuccessStatusCode(); + } + [Fact] public void CreateDefaultBuilder_RegistersRouting() { From dd0e40daca501a83114c1003239ade8fa78deda2 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Thu, 26 Jun 2025 01:03:40 +0800 Subject: [PATCH 02/10] feat: add config support for KnownNetworks and KnownProxies --- .../src/ForwardedHeadersOptionsSetup.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs index f55019e9f115..baf54f05c642 100644 --- a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs +++ b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs @@ -46,5 +46,17 @@ public void Configure(ForwardedHeadersOptions options) // being enabled by explicit configuration. options.KnownNetworks.Clear(); options.KnownProxies.Clear(); + + var knownNetworks = _configuration["ForwardedHeaders_KnownNetworks"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; + foreach (var network in knownNetworks) + { + options.KnownNetworks.Add(IPNetwork.Parse(network)); + } + + var knownProxy = _configuration["ForwardedHeaders_KnownProxies"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; + foreach (var network in knownNetworks) + { + options.KnownNetworks.Add(IPAddress.Parse(network)); + } } } From fd98a3341bb5e67aa360638d881c28376a911dd7 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Thu, 26 Jun 2025 01:05:50 +0800 Subject: [PATCH 03/10] fix: fix support for KnownProxies --- src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs index baf54f05c642..03045feaac76 100644 --- a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs +++ b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs @@ -53,10 +53,10 @@ public void Configure(ForwardedHeadersOptions options) options.KnownNetworks.Add(IPNetwork.Parse(network)); } - var knownProxy = _configuration["ForwardedHeaders_KnownProxies"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; - foreach (var network in knownNetworks) + var knownProxies = _configuration["ForwardedHeaders_KnownProxies"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; + foreach (var proxy in knownProxies) { - options.KnownNetworks.Add(IPAddress.Parse(network)); + options.KnownProxies.Add(IPAddress.Parse(proxy)); } } } From 458941b9d6490ca514f3233d3754b16a40ba329e Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Thu, 26 Jun 2025 07:23:45 +0800 Subject: [PATCH 04/10] fix: specific IPAddress namespace --- src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs index 03045feaac76..4fc2cd066cef 100644 --- a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs +++ b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs @@ -56,7 +56,7 @@ public void Configure(ForwardedHeadersOptions options) var knownProxies = _configuration["ForwardedHeaders_KnownProxies"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; foreach (var proxy in knownProxies) { - options.KnownProxies.Add(IPAddress.Parse(proxy)); + options.KnownProxies.Add(System.Net.IPAddress.Parse(proxy)); } } } From 7c4864060b1233c0e399d9b166ccddec96ebcc05 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Sat, 26 Jul 2025 00:25:48 +0800 Subject: [PATCH 05/10] feat: update forwarded headers options setup to use IPNetwork --- .../src/ForwardedHeadersOptionsSetup.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs index a6479d55de04..1fd80f21f177 100644 --- a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs +++ b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; +using System.Net; namespace Microsoft.AspNetCore; @@ -50,16 +50,22 @@ public void Configure(ForwardedHeadersOptions options) options.KnownIPNetworks.Clear(); options.KnownProxies.Clear(); - var knownNetworks = _configuration["ForwardedHeaders_KnownNetworks"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; + var knownNetworks = _configuration["ForwardedHeaders_KnownIPNetworks"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; foreach (var network in knownNetworks) { - options.KnownNetworks.Add(IPNetwork.Parse(network)); + if (IPNetwork.TryParse(network, var ipNetwork)) + { + options.KnownIPNetworks.Add(ipNetwork); + } } var knownProxies = _configuration["ForwardedHeaders_KnownProxies"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; foreach (var proxy in knownProxies) { - options.KnownProxies.Add(System.Net.IPAddress.Parse(proxy)); + if (IPAddress.TryParse(proxy, out var ipAddress)) + { + options.KnownProxies.Add(ipAddress); + } } } } From bd763e97d0cde0ffc415035cb5dc4f18db49cadd Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Sat, 26 Jul 2025 01:25:11 +0800 Subject: [PATCH 06/10] Update ForwardedHeadersOptionsSetup.cs --- src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs index 1fd80f21f177..cb8be5abfe6b 100644 --- a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs +++ b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs @@ -53,7 +53,7 @@ public void Configure(ForwardedHeadersOptions options) var knownNetworks = _configuration["ForwardedHeaders_KnownIPNetworks"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; foreach (var network in knownNetworks) { - if (IPNetwork.TryParse(network, var ipNetwork)) + if (IPNetwork.TryParse(network, out var ipNetwork)) { options.KnownIPNetworks.Add(ipNetwork); } From 1946c55809301f27041664568338110cd61035df Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Sat, 26 Jul 2025 07:17:09 +0800 Subject: [PATCH 07/10] Update ForwardedHeadersOptionsSetup.cs --- src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs index cb8be5abfe6b..e96819550a48 100644 --- a/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs +++ b/src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; -using System.Net; namespace Microsoft.AspNetCore; @@ -53,7 +53,7 @@ public void Configure(ForwardedHeadersOptions options) var knownNetworks = _configuration["ForwardedHeaders_KnownIPNetworks"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; foreach (var network in knownNetworks) { - if (IPNetwork.TryParse(network, out var ipNetwork)) + if (System.Net.IPNetwork.TryParse(network, out var ipNetwork)) { options.KnownIPNetworks.Add(ipNetwork); } @@ -62,7 +62,7 @@ public void Configure(ForwardedHeadersOptions options) var knownProxies = _configuration["ForwardedHeaders_KnownProxies"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) ?? []; foreach (var proxy in knownProxies) { - if (IPAddress.TryParse(proxy, out var ipAddress)) + if (System.Net.IPAddress.TryParse(proxy, out var ipAddress)) { options.KnownProxies.Add(ipAddress); } From 5a40ff6ac1632ddb92719aa17f2ff87a13766efa Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Sat, 26 Jul 2025 08:05:59 +0800 Subject: [PATCH 08/10] test: add test case for forwarded headers/networks/proxies --- .../WebHostTests.cs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs index 4f93c6f4050d..2612905c7b24 100644 --- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs +++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs @@ -6,10 +6,11 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.HostFiltering; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Constraints; using Microsoft.AspNetCore.TestHost; -using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -115,6 +116,34 @@ public async Task WebHostConfiguration_EnablesForwardedHeaders_CustomHeaders_Fro result.EnsureSuccessStatusCode(); } + [Fact] + public void WebHostConfiguration_EnablesForwardedHeaders_CustomConfig() + { + using var host = WebHost.CreateDefaultBuilder() + .ConfigureAppConfiguration(configBuilder => + { + configBuilder.AddInMemoryCollection(new[] + { + new KeyValuePair("FORWARDEDHEADERS_ENABLED", "true" ), + new KeyValuePair("FORWARDEDHEADERS_HEADERS", "XForwardedHost,XForwardedProto,XForwardedFor,XForwardedFor123" ), + new KeyValuePair("ForwardedHeaders_KnownIPNetworks", "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"), + new KeyValuePair("ForwardedHeaders_KnownProxies", "127.0.0.1") + }); + }) + .UseTestServer() + .Build(); + var forwardedHeadersOptions = host.Services.GetRequiredService>().Value; + Assert.NotNull(forwardedHeadersOptions); + Assert.Equal( + ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, + forwardedHeadersOptions.ForwardedHeaders + ); + Assert.NotEmpty(forwardedHeadersOptions.KnownIPNetworks); + Assert.Contains(forwardedHeadersOptions.KnownIPNetworks, network => network.Contains(System.Net.IPAddress.Parse("192.168.0.123"))); + Assert.NotEmpty(forwardedHeadersOptions.KnownProxies); + Assert.Contains(forwardedHeadersOptions.KnownProxies, proxy => proxy == System.Net.IPAddress.Parse("127.0.0.1")); + } + [Fact] public void CreateDefaultBuilder_RegistersRouting() { From 8ddff3d91d038fcb070facab95c7f3d72cf90985 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Sat, 26 Jul 2025 11:08:58 +0800 Subject: [PATCH 09/10] test: update test case --- .../WebHostTests.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs index 2612905c7b24..8cfea490e5f5 100644 --- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs +++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs @@ -117,7 +117,7 @@ public async Task WebHostConfiguration_EnablesForwardedHeaders_CustomHeaders_Fro } [Fact] - public void WebHostConfiguration_EnablesForwardedHeaders_CustomConfig() + public async Task WebHostConfiguration_EnablesForwardedHeaders_CustomConfig() { using var host = WebHost.CreateDefaultBuilder() .ConfigureAppConfiguration(configBuilder => @@ -125,17 +125,32 @@ public void WebHostConfiguration_EnablesForwardedHeaders_CustomConfig() configBuilder.AddInMemoryCollection(new[] { new KeyValuePair("FORWARDEDHEADERS_ENABLED", "true" ), - new KeyValuePair("FORWARDEDHEADERS_HEADERS", "XForwardedHost,XForwardedProto,XForwardedFor,XForwardedFor123" ), + new KeyValuePair("FORWARDEDHEADERS_HEADERS", "XForwardedHost,XForwardedProto,XForwardedFor123" ), new KeyValuePair("ForwardedHeaders_KnownIPNetworks", "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"), new KeyValuePair("ForwardedHeaders_KnownProxies", "127.0.0.1") }); }) .UseTestServer() + .Configure(app => + { + Assert.True(app.Properties.ContainsKey("ForwardedHeadersAdded"), "Forwarded Headers"); + app.Run(context => + { + Assert.Equal("https", context.Request.Scheme); + return Task.CompletedTask; + }); + }) .Build(); + await host.StartAsync(); + var client = host.GetTestClient(); + client.DefaultRequestHeaders.Add("x-forwarded-proto", "https"); + var result = await client.GetAsync("http://localhost/"); + result.EnsureSuccessStatusCode(); + var forwardedHeadersOptions = host.Services.GetRequiredService>().Value; Assert.NotNull(forwardedHeadersOptions); Assert.Equal( - ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor, + ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto, forwardedHeadersOptions.ForwardedHeaders ); Assert.NotEmpty(forwardedHeadersOptions.KnownIPNetworks); From 58128296eb61f717c515c331cc1abb57d95d9e24 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Sat, 26 Jul 2025 13:48:09 +0800 Subject: [PATCH 10/10] test: Update WebHostTests IPAddress test --- .../test/Microsoft.AspNetCore.Tests/WebHostTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs index 8cfea490e5f5..75b977724d90 100644 --- a/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs +++ b/src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/WebHostTests.cs @@ -156,7 +156,7 @@ public async Task WebHostConfiguration_EnablesForwardedHeaders_CustomConfig() Assert.NotEmpty(forwardedHeadersOptions.KnownIPNetworks); Assert.Contains(forwardedHeadersOptions.KnownIPNetworks, network => network.Contains(System.Net.IPAddress.Parse("192.168.0.123"))); Assert.NotEmpty(forwardedHeadersOptions.KnownProxies); - Assert.Contains(forwardedHeadersOptions.KnownProxies, proxy => proxy == System.Net.IPAddress.Parse("127.0.0.1")); + Assert.Contains(forwardedHeadersOptions.KnownProxies, System.Net.IPAddress.IsLoopback); } [Fact]