I am trying to get the remote IP address of a request (i.e., the IP of the client who sent the request) in my ASP.Net Core 2.1 MVC Controller (runs in .Net Docker container). Taking into consideration that My ASP.Net Core application is located behind NGINX reverse proxy (runs in NGINX Docker container).
As known, when the reverse proxy redirects the request to my .Net Core application, it will change the source IP of my request (TCP/IP layer), therefore, I configured NGINX to add X-Forwarded-For
with the original IP to the request. The request that is redirected from NGINX container to .Net container has X-Forwarded-For
in the header:
And of course, I configured .Net Core to know about that:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
{
// Rewrite the header when being redirected (this is required because we are behind reverse proxy)
var forwardedHeadersOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
KnownProxies = { IPAddress.Parse("172.20.10.2"), IPAddress.Parse("172.20.10.3"), IPAddress.Parse("172.20.10.4") },
};
forwardedHeadersOptions.KnownNetworks.Add(
new IPNetwork(IPAddress.Parse("172.0.0.0"), 8));
forwardedHeadersOptions.KnownNetworks.Add(
new IPNetwork(IPAddress.Parse("127.0.0.1"), 8));
app.UseForwardedHeaders(forwardedHeadersOptions);
...
However, HTTPContext.Connection.RemoteIPAddress
still returning 172.20.10.3 (NGINX container IP, not the real remote IP):
logger.LogDebug("Remote IP Address: " + Request.HttpContext.Connection.RemoteIpAddress.ToString());
Remote IP Address: 172.20.10.3
I checked my header in .Net Core, it has X-Forwarded-For
with the correct original remote IP address:
logger.LogDebug("X-Forwarded-For Header Feature: " + HttpContext.Request.Headers["X-Forwarded-For"]);
X-Forwarded-For Header Feature: 85.XX.4.121
Does someone have any idea what I am missing? Why RemoteIPAddress still returning the IP of the NGINX docker container instead of the real remote IP address?
My Program.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:5000")
.UseStartup<Startup>()
.Build();
}
I tried Also to configure the the ForwarededHeadersOptions
by configuring its service like this:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
//options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("172.0.0.0"), 8));
options.RequireHeaderSymmetry = false;
options.ForwardLimit = null;
options.KnownProxies.Add(IPAddress.Parse("172.20.10.3"));
//options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("127.0.0.1"), 8));
});
With no success...
OK I guess I am on the right way, the IP address returned by RemoteIPAddress
was ::ffff:172.20.10.20, not 172.20.10.20! I did not know that they are different. The official documentation helped me to discover that.
UseForwardedHeaders(IApplicationBuilder) Applies forwarded headers to their matching fields on the current request. By convention, HTTP proxies forward information from the client in well-known HTTP headers. The ForwardedHeadersMiddleware reads these headers and fills in the associated fields on HttpContext.
A reverse proxy is a special type of proxy server that hides the target server to the client. The client requests a resource to the proxy server which retrieves it from another server and provides it to the client. In this case, the client has no idea that the resource comes from another server.
Request. Headers["X-Forwarded-For"]. Split(new char[] { ',' }). FirstOrDefault();
The IP I got from RemoteIPAddress
was IPv4 represented as IPv6 (was ::ffff:172.20.10.20, not 172.20.10.20!). I was using only IPv4 part of the IP, therefore the KnownProxies
in my case were wrong. I should have entered the full IPv4 address also with the v6 representation part.
The official documentation showed that:
https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1
So in my case, the code should look like this:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.RequireHeaderSymmetry = false;
options.ForwardLimit = null;
options.KnownProxies.Add(IPAddress.Parse("::ffff:172.20.10.20")); // <<-- Notice the full format of the IP address.
});
As per the official documentation, if you are using Apache or Nginx integration, following code should be added to the Startup.ConfigureServices
method.
// using Microsoft.AspNetCore.HttpOverrides;
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default.
// Clear that restriction because forwarders are enabled by explicit
// configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
and then on top of everything, in Configure
method use
app.UseForwardedHeaders();
Further suppose in nginx conf file, inside a location, use
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
Now the first entry in the X-Forwarded-For
will be the real client IP.
IMPORTANT: If you want to secure the app and not allow an attacker inject X-Forwarded-For, Please read this answer.
Please see Forward the scheme for Linux and non-IIS reverse proxies, Configure Nginx and Dealing with invalid headers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With