skip to Main Content

From apache docs (https://httpd.apace.org/docs/2.4/mod/mod_remoteip.html) we implemented the following assignment on our server:

RemoteIPHeader X-Forwarded-For

to get a client’s IP rather than the ELB’s IP. However, we didn’t notice that the ELB also appends all other X-Forwarded-For values to the left of that string. So this is not a secure way to get a client’s IP.

We’ve used LogFormat with "%{X-Forwarded-For}i" to verify the values being passed in are as documented.

192.168.0.0, 10.0.0.0

is what would come through if 192.168.0.0 were the header being passed and 10.0.0.0 were the client’s requesting machine. A standard request without the header would be:

10.0.0.0

Is there a way to extract the rightmost IP? I was thinking something like,

RemoteIPHeader ('(?:d{1,3}[.]){3}d{1,3}$', X-Forwarded-For,)[0]

but can’t find a function in apache to configure this. I could do this in PHP but then my logs will all have the wrong IPs logged.

I’ve tried:

SetEnvIf X-Forwarded-For '((?:d{1,3}[.]){3}d{1,3})$' ip_is=$1
RemoteIPHeader %{ip_is}

but this didn’t take affect.

Update:

Apache configuration runs with:

LogFormat "%{%Y-%m-%d %H:%M:%S}t %a %u %A %p %m %U %q %>s "%{User-agent}i" %T/%D "%{X-Forwarded-For}i"" w3c_extended
CustomLog /var/log/httpd/example.com/access.log w3c_extended

I currently receive either:

2021-02-27 14:29:06 10.0.21.150 - 10.0.20.222 443 GET /IPtest.php ?v=1 200 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" 0/2822 "73.149.97.219"

or

2021-02-27 14:29:06 10.0.21.150 - 10.0.20.222 443 GET /IPtest.php ?v=1 200 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" 0/2822 "10.0.21.150, 73.149.97.219"

I need to capture 73.149.97.219 in both scenarios.

2

Answers


  1. I’m testing with apache 2.4 and remoteIP

    RemoteIPHeader x-forwarded-for
    

    You’ll also need to tell your apache what the internal IP address of your Load balancer (Reverse Proxy) is. There is no reliable easy way to determine that internal IP and it can by ‘any’ RFC1918 (private) IP address
    So you’ll need to add those 3 subnets.

    RemoteIPTrustedProxy 10.0.0.0/8
    RemoteIPTrustedProxy 172.16.0.0/12
    RemoteIPTrustedProxy 192.168.0.0/16
    

    and then use %a for the logFormat

    LogFromat %a
    

    i’ve tested with

    RemoteIPTrustedProxy 127.0.0.1
    LogFormat "%a %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
    

    tested with curl

    curl 127.0.0.1/so 
    127.0.0.1 - - [27/Feb/2021:15:02:38 +0100] "GET /so/ HTTP/1.1" 200 167 "-" "curl/7.52.1"
    
    curl 127.0.0.1/so/ -H "x-forwarded-for:  1.2.3.4"
    1.2.3.4 - - [27/Feb/2021:15:04:06 +0100] "GET /so/ HTTP/1.1" 200 167 "-" "curl/7.52.1"
    
    curl 127.0.0.1/so/ -H "x-forwarded-for:  8.5.4.1, 1.2.3.4"
    1.2.3.4 - - [27/Feb/2021:15:04:31 +0100] "GET /so/ HTTP/1.1" 200 167 "-" "curl/7.52.1"
    
    Login or Signup to reply.
  2. I got this problem in different context – apache was resolving hostnames from manipulated X-Forwarded-For header. E.g. X-Forwarded-For: mumblemuble.burpcollaborator.com, 1.1.1.1, anotherdomainapachewillresolve.com

    My solution was to modify the X-Forwarded-For header to only include the IP address added by ELB, and discard IP addresses which ELB appended to the header.

    Instead of other reverse proxies, ELB appends existing X-Forwarded-For addresses and hostname before the client IP. For other reverse proxies you should modify regexp to discard everything after first comma.

    # because of "early", headers can only be set in a main server or virtual host context. 
    RequestHeader edit  "X-Forwarded-For" "^(.+),(.+)$" "$2" early
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search