Why is it not good to use this function and how do I identify the user’s IP then?

Asked

Viewed 299 times

2

public function get_client_ip() {
                $ipaddress = '';
                if (isset($_SERVER['HTTP_CLIENT_IP']))
                    $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
                else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
                    $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
                else if(isset($_SERVER['HTTP_X_FORWARDED']))
                    $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
                else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
                    $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
                else if(isset($_SERVER['HTTP_FORWARDED']))
                    $ipaddress = $_SERVER['HTTP_FORWARDED'];
                else if(isset($_SERVER['REMOTE_ADDR']))
                    $ipaddress = $_SERVER['REMOTE_ADDR'];
                else
                    $ipaddress = 'Desconhecido';

                return $ipaddress;
        }

This code is not good because have security problems I’ve seen several times saying here on the forum

How do I get the ip then? IN PHP

  • How about you help me?

1 answer

5

Because you trust the header sent by the client, simple as that. This allows the client to falsify the IP, allowing IP Spoofing.

Basically the rule is "Never trust any header" in the same way that you should never trust a cookie (which is also a header).


How to attack this code? You can test it yourself!

  • Server:

    echo 'IP deste codigo: ' . get_client_ip();
    echo PHP_EOL;
    echo 'IP real:         ' . $_SERVER['REMOTE_ADDR'];
    
  • Client:

    curl http://seusite.com -H "CLIENT-IP: 111.222.333.444"
    

The curl is a software for making requests, the parameter -H adds a header, in this case with the name of CLIENT-IP with the value of 111.222.333.444. There are several software capable of doing this too, the curl I think it’s the most used, but far from being unique.


For "simulation" I used a notebook as client (IP is 192.168.100.196) and a desktop as server (IP is 192.168.100.122) that had the above code, both on the same network, so I ran:

curl http://192.168.100.122/iptester.php -H "CLIENT-IP: 111.222.333.444"

Upshot:

IP deste codigo: 111.222.333.444
IP real:         192.168.100.196

Okay, we have a fake IP! We can ignore any IP restriction! >:D

Note that your function relies on the sent header. This could be even more severe because as we are using echo get_client_ip(); being vulnerable to XSS, after all:

CLIENT-IP: <script>alert('xss')</script>

This would run in the browser because there is no filter.


If you want to attack using PHP itself, then also use Curl:

$alvo = 'http://192.168.100.122/iptester.php';
$ipFalso = '111.222.333.444';

$curl = curl_init($alvo);

curl_setopt_array($curl, [

    CURLOPT_HTTPHEADER => [
        'CLIENT-IP:' . $ipFalso,
        'X-FORWARDED-FOR:' . $ipFalso,
        'X-FORWARDED:' . $ipFalso,
        'FORWARDED-FOR:' . $ipFalso,
        'FORWARDED:' . $ipFalso,
    ],

]);

curl_exec($curl);

Assuming that the http://192.168.100.122/iptester.php contains the example code mentioned above. ;)

  • I was in doubt @Inkeliz. It is preferable that I use $_SERVER then?

  • Yes, use the $_SERVER['REMOTE_ADDR'], except if you use Cloudflare (or other proxy), then you use the headers offered by them.

  • This value in $_SERVER is defined by the server itself, certain?

  • 1

    It is defined by the webserver itself (Apache/Nginx), it informs the IP of the client you are accessing, unless it is configured wrong. It is much harder to fake this than a simple header. There are some Cves about similar cases to this code, for example from Cakephp and there is a CWE about it. There are several issues on Github about, this is one and recommendation is to use the $_SERVER['REMOTE_ADDR'].

  • So I must always wear REMOTE_ADDR, never other, because they can be modified with some program? What is the meaning of the existence of others then?

  • 1

    @Guilhermecostamilam, yes. The REMOTE_ADDR is more reliable because it is provided by the web server. There are exceptions, as said in the comments, especially if using some reverse proxy, like Cloudflare, Incapsula or Sucuri.... Ignoring these "Cloudflares", if you have cache servers, which also act as proxy, it may be that the REMOTE_ADDR end up getting the local IP from this other server. But, this is a matter of the server configuration architecture, not PHP specifically.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.