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