Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can nginx handle duplicate X-Forwarded-For headers?

Tags:

php

nginx

When user using proxy (Google data saver etc), the browser adds X-Forwarded-For for clients' real ip address to server. Our load balancer passes all headers + the clients' ip address as X-Forwarded-For header to nginx server. The example request headers:

X-Forwarded-For: 1.2.3.4
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Host: *.*.*.*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,tr;q=0.6
Save-Data: on
Scheme: http
Via: 1.1 Chrome-Compression-Proxy
X-Forwarded-For: 1.2.3.5
Connection: Keep-alive

Is there any way to pass both of the X-Forwarded-For headers to php, respectively?

like image 776
onesvat Avatar asked Jan 06 '23 12:01

onesvat


1 Answers

TL;DR

  • nginx: fastcgi_param HTTP_MERGED_X_FORWARDED_FOR $http_x_forwarded_for
  • php: $_SERVER['HTTP_MERGED_X_FORWARDED_FOR']

Explanation

You can access all http headers with the $http_<header_name> variable. When using this variable, nginx will even do header merging for you so

CustomHeader: foo
CustomHeader: bar

Gets translated to the value:

foo, bar

Thus, all you need to do is pass this variable to php with fastcgi_param

fastcgi_param HTTP_MERGED_X_FORWARDED_FOR $http_x_forwarded_for

Proof of concept:

in your nginx server block:

location ~ \.php$ {
    fastcgi_pass unix:run/php/php5.6-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param HTTP_MERGED_X_FORWARDED_FOR $http_x_forwarded_for;
    include fastcgi_params;
}

test.php

<?php
die($_SERVER['HTTP_MERGED_X_FORWARDED_FOR']);

And finally see what happens with curl:

curl -v -H 'X-Forwarded-For: 127.0.0.1' -H 'X-Forwarded-For: 8.8.8.8' http://localhost/test.php

Gives the following response:

* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /test.php HTTP/1.1
> Host: localhost
> User-Agent: curl/7.47.0
> X-Forwarded-For: 127.0.0.1
> X-Forwarded-For: 8.8.8.8
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.3 (Ubuntu)
< Date: Wed, 01 Nov 2017 09:07:51 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
127.0.0.1, 8.8.8.8

Boom! There you go, you have access to all X-FORWARDED-FOR headers, as a comma-delimited string in $_SERVER['HTTP_MERGED_X_FORWARDED_FOR']

Of course, you can use whatever name you want and not just HTTP_MERGED_X_FORWARDED_FOR.

like image 69
Aron Cederholm Avatar answered Jan 13 '23 09:01

Aron Cederholm