Score:0

Read "source IP" from a forwarded connection

mq flag

My firewall is working ok: the connection from internet is forwarded to a NGINX server, which then distribute accordingly and application server works correctly except for the internal LOGs.

The issue I'm facing is regarding the IP being received by our application server: they are not the "client IP", instead, they are currently the NGINX IP.

Consider this network: client IP 1, firewall IP 2, NGINX IP 3, webserver IP 4.

At firewall we see the packets being forwarded to the NGINX, but at NGINX with tcpdump we see incoming connections from own NGINX IP 3 instead of original source IP 1.

The point is that at webserver LOGs we see our input connections as IP 3, expected is IP 1.

Is it a misconfiguration with firewall or NGINX? Any ideas on how to solve this?

Current config (/etc/nginx/sites-enabled/app.domain.com):

...
location ^~ / {
proxy_pass      http://10.0.0.11;
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-Proto       $scheme;
}
...
Lex Li avatar
vn flag
What is the actual web server you are referring to? There are tons of articles for each major web server (such as [this kind](https://blogs.iis.net/deanc/iis7-8-logging-the-real-client-ip-in-the-iis-hit-logs) for IIS) talking about how to record real IP in log files. The answer below also provides some insights.
Score:1
us flag

This is normal operation. When nginx is a reverse proxy, it opens a connection to the final destination and proxies from the client to the application server. The source IP cannot be anything else than nginx IP address, otherwise the TCP connection would not work.

You need to set up the application server to use the IP address specified in X-Real-IP header instead of the IP address from the TCP connection.

Score:0
mq flag

Solution for this case was to change c# code as below. No firewall or nginx changes made.

var userIP = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

Previous unsuccessful attempts:

var userIP = Request.ServerVariables["X_FORWARDED_FOR"];
var userIP = Request.ServerVariables["X-REAL-IP"];
var userIP = Request.ServerVariables["REMOTE_ADDR"];
var userIP = Request.UserHostAddress;

Thanks for all contributors to help clarify that the issue was not at firewall nor at nginx config.

Nikita Kipriyanov avatar
za flag
Beware of security. You should use those headers only if the connection came from trusted peer; otherwise, log the peer IP address and better treat it as a breach attempt. Imagine the request came into your server around reverse proxy, that exploits some vulnerability, and it contains "X-Real-IP" of some innocent computer as a decoy. Accordingly, you must ensure your reverse proxy always replaces such headers in incoming requests with its own before proxying, and never lets them to pass through.
rd1218 avatar
mq flag
The IP is being recorded for login, session renewal, logout and error situation for historical events only. The IP is being sanitized before sent to DB, and nothing more is being done with this information. Do you see any concerns about this? Regarding the second part (header replacement), should I change the current ```nginx.conf``` lines shown, or maybe add some lines?
Nikita Kipriyanov avatar
za flag
I meant you only can trust the IP address from the header if you know who set it. The HTTP headers must be regarded as client input, and their contents is, generally, unsafe. This was the point. To use them safely, you must ensure only you control their contents, and nobody else. For your case: it seems Nginx configuration is safe (Nginx is configured to sanitize the X-Forwarded-For), but the application must check the peer IP address and only use data from the header if the peer IP address is actually Nginx.
rd1218 avatar
mq flag
Thanks. Do you have any suggestion on how can I set the application to check where that IP is from? Currently our application receives requests from Internet (via firewall and then via Nginx) and also from within our intranet (our team inside the office).
Nikita Kipriyanov avatar
za flag
Add a condition for setting `userIP`. Something like: `if (Request.ServerVariables["REMOTE_ADDR"] == TrustedIP) { Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; } else { userIP = Request.ServerVariables["REMOTE_ADDR"]; }`. I am not sure the syntax is correct but the semantics should be like this. `TrustedIP` is an object (probably, a configuration setting) that holds reverse proxy IP address (its peer address from you see proxied connections). Or you may make a set and check that `REMOTE_ADDR` belogns to that set, that would be the most generic solution.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.