Add ability to detect real developer IP on remote server

3 years ago

Slava.Aurim
Member | 14
+
0
-

Hello guys!

Tracy is awesome & very esthetic! But unfortunately it does not detect real ip-addreses of developer on remote host, if server is behind the proxy.

I had such problem on the remote server of my hosting provider: $_SERVER[‘REMOTE_ADDR’] was changed on each request. And the code below did not show Tracy on remote server:

// exit( $_SERVER['REMOTE_ADDR'] ); // uncomment to see ip-address
$developerIp = '92.55.170.174';
\Tracy\Debugger::enable($developerIp);

To solve the problem, I inspected the $_SERVER to find the real IP. And later I found a good function on stackoverflow.com and slightly modified it. The code below is dirty solution but it works for me:

$developerIp = '92.55.175.209';
$userIp = getRealIp();

//exit($userIp); // uncomment to see ip-address

$debugMode =  $userIp === $developerIp ? \Tracy\Debugger::DEVELOPMENT : \Tracy\Debugger::DETECT;
\Tracy\Debugger::enable($debugMode);

And this the function to get real IP:
(Please, check if it is right and settles the most of cases?)

function getRealIp()
    {
        $proxyHeaders = [
            'CLIENT_IP',
            'FORWARDED',
            'FORWARDED_FOR',
            'FORWARDED_FOR_IP',
            'HTTP_CLIENT_IP',
            'HTTP_FORWARDED',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED_FOR_IP',
            'HTTP_PC_REMOTE_ADDR',
            'HTTP_PROXY_CONNECTION',
            'HTTP_VIA',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_X_FORWARDED',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED_FOR_IP',
            'HTTP_X_IMFORWARDS',
            'HTTP_XROXY_CONNECTION',
            'VIA',
            'X_FORWARDED',
            'X_FORWARDED_FOR',

        ];

        // check is there some proxy header?
        foreach ($proxyHeaders as $proxyHeader)
        {
            if (!isset($_SERVER[$proxyHeader])) {
                continue;
            }
            $IP = $_SERVER[$proxyHeader];

            // extract 1-st IP (it's real) from comma-list
            // for example: [HTTP_X_FORWARDED_FOR] => 92.55.170.174, 66.102.9.80
            if (strpos($IP, ',')) {
                list($IP) = explode(',', $IP);
            }

            // cut out the port number
            if (strpos($IP, ':')) {
                list($IP) = explode(':', $IP);
            }

            // check is valid IP
            if (filter_var($IP, FILTER_VALIDATE_IP)) {
                return $IP;
            }
        }

        // return standart IP property if no proxy was found
        return $_SERVER['REMOTE_ADDR'];
    }

I suggest to add this function to Tracy\Debugger (or maybe in Nette\Http\Request ?) , and use it from Tracy\Debugger::detectDebugMode method.

Last edited by Slava.Aurim (2016-08-13 15:26)

3 years ago

pata.kusik111
Member | 74
+
+2
-

Hello,
a functionality similar to this, eg recognition of http_x_forwarded and forwarded headers can be found in http\requestFactory. However there is one issue, why this cannot be easily directly implemented in Tracy. Or at least not with the function you suggested. Your function does not work for some headers and IPv6 (for example look at Forwarded header specification) and you have no validation, whether the headers were sent from trusted proxy. Then if would be very easy to forge the headers, especially of servers without proxy.

I am not saying it is not possible, just that the issue is much more complicated that you painted here.

3 years ago

Slava.Aurim
Member | 14
+
0
-

Do I understand right, that my solution is not safe enough? How to solve it by simple way?

  1. Check whether the Http\RequestFactory all kinds of proxy header?
  2. Can I pass to RequestFactory ip-range of trusted proxy-ip, like ‘92.55.175.*’, in order to avoid forging forwarded headers?
  3. Can you show me simple example – how get real user ip using RequestFactory with passed trusted proxy ip-range?
  4. Whether it's excessive overhead – using Http\RequestFactory for initializing Tracy\Debugger?
  5. Is there another simple way (not using IP) to identify developer and enable the debugger for it?

I would be very grateful for your help!

Last edited by Slava.Aurim (2016-08-19 06:12)

3 years ago

Jan Tvrdík
Nette guru | 2556
+
0
-

@Slava.Aurim Using Http\RequestFactory with IP range for trusted proxy is quite simple

$httpRequestFactory = new Http\RequestFactory();
$httpRequestFactory->setProxy('92.55.175.0/24'); // 92.55.175.0 - 92.55.175.255
$httpRequest = $httpRequestFactory->createHttpRequest();
$realIp = $httpRequst->getRemoteAddress();

Whether it's excessive overhead – using Http\RequestFactory for initializing Tracy\Debugger?

Http\RequestFactory is very fast, but does handle a lot more stuff than just getting real IP address. However tracy/tracy cannot depend o nette/http.

3 years ago

Slava.Aurim
Member | 14
+
0
-

@JanTvrdík thanks for example! And what does mean “0/24”? I looked into the method Nette\Http\Helpers::ipMatch($ip, $mask), but was not able to understand how it works. Argument $mask is extremely non-obvious. Could you give me several examples for correct ip masks and explain it format? In my opinion, it would be more obvious format for proxy ip-range: '92.55.175.*' or ['92.55.175.0', '92.55.175.255'] or maybe even a list of ranges: ['92.55.175.0-92.55.175.100', '92.55.175.200-92.55.175.255']

Last edited by Slava.Aurim (2016-08-19 18:58)

3 years ago

jiri.pudil
Member | 861
+
+2
-

It's a standard CIDR notation

3 years ago

Slava.Aurim
Member | 14
+
+2
-

Did I understand correctly that number after slash indicates the size in bits of the lead (left) invariable part of the ip address? And the maximum size (for ipv4) is 32 bits?

Last edited by Slava.Aurim (2016-08-19 19:44)

3 years ago

Slava.Aurim
Member | 14
+
0
-

Maybe someone find useful this CIDR tool. For a better understanding of the concept of cidr addressing, you can use CIDR Address Range calculator: http://www.subnet-calculator.com/cidr.php