PHP most accurate / safe way to get real user IP a

2020-02-27 18:23发布

What is the most accurate way to get user's IP address in 2017 via PHP?

I've read a lot of SO questions and answers about it, but most of answers are old and commented by users that these ways are unsafe.

For example, take a look at this question (2011): How to get the client IP address in PHP?

Tim Kennedy's answer contains a recommendation to use something like:

if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
    $ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    $ip = $_SERVER['REMOTE_ADDR'];
}

But as I've read a lot, I have seen that to use X_FORWARDED_FOR is unsafe, as the comment below highlights:

Do NOT use the above code unless you know EXACTLY what it does! I've seen MASSIVE security holes due to this. The client can set the X-Forwarded-For or the Client-IP header to any arbitrary value it wants. Unless you have a trusted reverse proxy, you shouldn't use any of those values.

As I didn't know EXACTLY what it does, I don't want to take the risk. He said it is unsafe, but did not provide a safe method to get user's IP address.

I've tried the simple $_SERVER['REMOTE_ADDR'];, but this returns the wrong IP. I've tested this and my real IP follows this pattern: 78.57.xxx.xxx, but I get an IP address like: 81.7.xxx.xxx

So do you have any ideas?

9条回答
狗以群分
2楼-- · 2020-02-27 18:48

I use this code, and it works for me. Take a look to it.

<?php

// Gets client's IP.
$ip = getenv("HTTP_CLIENT_IP")?:
getenv("HTTP_X_FORWARDED_FOR")?:
getenv("HTTP_X_FORWARDED")?:
getenv("HTTP_FORWARDED_FOR")?:
getenv("HTTP_FORWARDED")?:
getenv("REMOTE_ADDR");

echo $ip;

?>

Here, a working example. Hope it helps!

查看更多
别忘想泡老子
3楼-- · 2020-02-27 18:49

How about this one -

public function getClientIP()
    {
        $remoteKeys = [
            'HTTP_X_FORWARDED_FOR',
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR',
            'HTTP_X_CLUSTER_CLIENT_IP',
        ];

        foreach ($remoteKeys as $key) {
            if ($address = getenv($key)) {
                foreach (explode(',', $address) as $ip) {
                    if ($this->isValidIp($ip)) {
                        return $ip;
                    }
                }
            }
        }

        return '127.0.0.0';
    }


    private function isValidIp($ip)
    {
        if (!filter_var($ip, FILTER_VALIDATE_IP,
                FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)
            && !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE)
        ) {
            return false;
        }

        return true;
    }
查看更多
我命由我不由天
4楼-- · 2020-02-27 18:55

From a security POV, nothing but $_SERVER['REMOTE_ADDR'] is reliable - that's just the simple truth, unfortunately.

All the variables prefixed with HTTP_ are in fact HTTP headers sent by the client, and there there's no other way to transfer that information while requests pass through different servers.
But that of course automatically means that clients can spoof those headers.

You can never, ever trust the client.

Unless it is you ... If you control the proxy or load-balancer, it is possible to configure it so that it drops such headers from the original request.
Then, and only then, you could trust an e.g. X-Client-IP header, but really, there's no need to at that point ... your webserver can also be configured to replace REMOTE_ADDR with that value and the entire process becomes transparent to you.

This will always be the case, no matter which year we are in ... for anything related to security - only trust REMOTE_ADDR.
Best case scenario is to read the HTTP_ data for statistical purposes only, and even then - make sure that the input is at least a valid IP address.

查看更多
登录 后发表回答