Home > Software Development > Nginx: How to Find out Real Source of HTTP Request

Nginx: How to Find out Real Source of HTTP Request

February 19th, 2014 Leave a comment Go to comments

In a recent project using Nginx as reversed proxy server, I got into an interesting problem: how can the server behind the Nginx tell whether a HTTP request comes from remote host or local host? If I just look at the IP header of the request, they are all local because the reversed-proxied packets from remote seems to be sent from local as well. So I cannot really tell the source of a HTTP request.

Luckily, there is already an easy to do it with Nginx. While forwarding a packet to its destination defined in the configuration file, Nginx can add additional HTTP headers which can be read by the target server to tell whether the original source.

Lost VMs or Containers? Too Many Consoles? Too Slow GUI? Time to learn how to "Google" and manage your VMware and clouds in a fast and secure HTML5 App.

In the configuration, you can add proxy_set_header as follows: (For a full example of configuration file, check out this post)

http
{
  server
  {
    …
    location /
    {
         …
         proxy_set_header    X-Real-IP    $remote_addr;
        …
    }
  }
}

The HTTP request forwarded then has a new header with name like “X-Real-IP”. I actually see different variations for the header name with upper and lower cases, for example, “X-REAL-IP” or “x-real-ip”. It has not yet an issue for me because the API for retrieving the header value seems to be case insensitive. To be easy, I just assume it’s always lower cases. The value of the header can be “127.0.0.1” which indicates it’s from local; otherwise, it’s a different real IP address.

If you think a bit more, you would find a potential problem: what if a HTTP client fake a HTTP header? For example, a remote client adds a header with same name “x-real-ip” with “127.0.0.1”. Very fair concern and it seems to have been thought about. It turns out that if there is a header with the same name, Nginx would overwrite the value with a real source IP address. So this approach is pretty reliable.

Still, there is a potential problem. What if the client connects to the back end server directly? Then it can succeed to fool the back end server. To make sure it’s not the case, you want to block the back end server like Tomcat from responding direct requests as described in this article.

Categories: Software Development Tags: , ,
  1. Ben
    February 20th, 2014 at 06:42 | #1

    > It has not yet an issue for me because the API for retrieving the header value seems to be case insensitive.

    The API *must* handle header field names case-insensitive. HTTP-1.1 requires this as described in http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html

    If you need similar features for Apache HTTP servers, take a look at X-Forwarded-For and/or ProxyPreserveHost, depending on your needs at the backend server.

  2. February 20th, 2014 at 11:54 | #2

    Hi Ben,

    Thanks for the comment. You are right that the protocol itself says the header names are case sensitive. The API I used may have normalized the names so it gets me value regardless the cases in my header name. I felt a little strange while using it, but didn’t dig down.

    Steve

  1. No trackbacks yet.