Search code examples
amazon-web-servicesapacheapache2amazon-elbx-forwarded-for

AWS ELB Apache Get Client IP, Avoid X-Forwarded-For Spoofing


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.


Solution

  • 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"