3

Here is a few theories to get user's IP

Theory1: If you don't use a load balancer, use REMOTE_ADDR. If you use a load balancer, use whatever it uses. In 99% of cases that appears to be HTTP_X_FORWARDED_FOR. So:

function get_ip_address(){
    $id = '';
    if (isset($_SERVER['REMOTE_ADDR']))
        $ip = $_SERVER['REMOTE_ADDR']; 
    else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; 
    else
        $ip = 'UNKNOWN';
    return $ip;
}

Theory2: There is some other HTTP header information (ie. $_SERVER['HTTP_...]) which might be containing the IP. So:

function get_ip_address(){
    foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
        if (array_key_exists($key, $_SERVER) === true){
            foreach (explode(',', $_SERVER[$key]) as $ip){
                $ip = trim($ip); // just to be safe
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                    return $ip;
                }
            }
        }
    }
}

Theory3: Storing both one of $_SERVER['HTTP_...] and $_SERVER['REMOTE_ADDR']. So there is two variables:

function get_ip_address(){
    foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED') as $key){
        if (array_key_exists($key, $_SERVER) === true){
            foreach (explode(',', $_SERVER[$key]) as $ip2){
                $ip2 = trim($ip2); // just to be safe
                if (filter_var($ip2, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                    $ip1 = $_SERVER['REMOTE_ADDR'];
                    return array($ip2, ip1);
                }
            }
        }
    }
}

Well honestly I'm confused a little bit. How many column (in the database) do I need to store the user's IP? I mean should I store both REMOTE_ADDR and a HTTP_...? Or just one of them?

Actually I have a query which inserts the user's IP per each page loading in the database. So that query will be executed every time before loading of the page. Surely an INSERT query (everytime for each request, and each user) has a cost. So I don't want it be useless. I mean I want to store a correct/real IP or at least I want to do the best work which is possible to detect the user's IP * .

* When an user uses a proxy like HSS then detecting him would be impossible. That's why I said "at least".

Ok well, which theory is the best?

Martin AJ
  • 6,261
  • 8
  • 53
  • 111
  • You need only one. You shouldn't really rely on HTTP headers as they can be changed on the client. You should only use any of those `HTTP_X_FORWARDED_...` (and any other) variables if you trust the information, i.e. if the connecting IP `REMOTE_ADDR` is a trusted load balancer or reverse proxy. – Charlotte Dunois Jul 08 '16 at 22:27
  • You can also configure the webserver to put `X-FORWARDED-FOR` into `REMOTE-ADDRESS` automatically, so that you don't have to do that in every script. – Barmar Jul 08 '16 at 22:32
  • You seem to be asking this question from a database load / performance aspect instead of asking what's the most accurate source for an IP address. If you're truly just concerned about the database aspect, the difference between storing one or two is negligible. – devlin carnate Jul 08 '16 at 22:32
  • @devlincarnate No database isn't my subject. I want to know how can I get the real IP. – Martin AJ Jul 08 '16 at 22:35
  • @Barmar Well I'm not familiar with webserver configuration. So I'm fine with doing that by PHP. Just I want to know should I store **both** `REMOTE-ADDRESS` and `X-FORWARDED-FOR` or **either** `REMOTE-ADDRESS` or `X-FORWARDED-FOR` ? – Martin AJ Jul 08 '16 at 22:37
  • I don't see any reason to store both. Whatever you decide is the actual IP, store that. – Barmar Jul 08 '16 at 22:38
  • @Barmar Well please read the middle paragraph of [this answer](http://stackoverflow.com/questions/3003145/how-to-get-the-client-ip-address-in-php#3003233) – Martin AJ Jul 08 '16 at 22:40
  • Like I said, you first decide which address you trust. If the remote address is a trusted proxy, you use the forwarded-for address. If it isn't, you ignore that header and use remote-address. – Barmar Jul 08 '16 at 22:42
  • @Barmar Always when I arrive to this I will be confused. Ok, what's *"the remote address"* and how can I understand whether is it *"a trusted proxy"*? – Martin AJ Jul 08 '16 at 22:45

2 Answers2

2

You need to decide when you're storing the IP whether you trust the remote address that's sending the X-FORWARDED-FOR address. If you do, then you store the forwarded address, otherwise you store the remote address. So it could be like this:

$load_balancer = '10.20.30.40';
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['X_FORWARDED_FOR'] && $ip = $load_balancer) {
    $ip = $_SERVER['X_FORWARDED_FOR'];
}

Then log $ip in the database.

I don't see any point in storing the load balancer IP in the database as well. Performing the trust check when processing the database data would require you to have another table that says what the load balancer IP was during different time periods.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Fist of all, why you don't care about the rest of cases? `HTTP_CLIENT_IP`, `HTTP_X_FORWARDED`, etc .. Second, what's this IP `10.20.30.40`? Honestly I don't know what's a *load balancer* .. – Martin AJ Jul 08 '16 at 22:52
  • You mentioned the load balancer in the second line of your question. – Barmar Jul 08 '16 at 23:01
  • 1
    A load balancer is a reverse proxy server that you use when you're running a cluster of servers. Clients connect to the load balancer, and it forwards the connection to one of the actual servers. If you're not using a load balancer, you don't need to worry about any of this stuff, just use `REMOTE_ADDR`. – Barmar Jul 08 '16 at 23:02
  • I see +1. So `$ip = $_SERVER['REMOTE_ADDR'];`, Just that? In this case what happens when the user uses a proxy like HSS? – Martin AJ Jul 08 '16 at 23:05
  • You can't trust headers sent by a proxy service you don't manage. So use `REMOTE_ADDR` when they use a public proxy like that. – Barmar Jul 08 '16 at 23:06
  • Overall I have to use `REMOTE_ADDR` as the IP *(for all cases)*. Ok, just what happens when `$_SERVER['REMOTE_ADDR']` is empty? I mean is that possible? – Martin AJ Jul 08 '16 at 23:08
  • No, it's not possible if PHP is being run on a server. – Barmar Jul 08 '16 at 23:11
  • Ah got it .. Based on your explanations all I need to store is just `REMOTE_ADDR`. So I'm wonder why the most of answers *([this](http://stackoverflow.com/questions/1634782/what-is-the-most-accurate-way-to-retrieve-a-users-correct-ip-address-in-php#2031935), [this](http://stackoverflow.com/questions/15699101/get-the-client-ip-address-using-php#15699240), [this](http://stackoverflow.com/questions/3003145/how-to-get-the-client-ip-address-in-php#55790))* are talking about the other thing like `HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR, HTTP_X_FORWARDED` – Martin AJ Jul 08 '16 at 23:16
  • Because there aren't commonly implemented standards for proxy servers and load balancers, so they send different headers. If you want to handle all the different proxies, you have to look for all those things. – Barmar Jul 08 '16 at 23:18
  • Ok, currently I'm on local, that's why I don't understand your mean of *"proxy servers"* or *"load balancer"*. Is there any good reference that I read it? – Martin AJ Jul 08 '16 at 23:20
  • Start with wikipedia. – Barmar Jul 08 '16 at 23:23
  • Alright .. just one thing: *"so **they** send different headers"*, "they" refers to what? Totally are you talking about my website's server or the server of my website's users? – Martin AJ Jul 08 '16 at 23:26
  • I'm talking about the proxy servers like HSS. – Barmar Jul 08 '16 at 23:32
  • Your webserver gets the remote IP from the TCP connection itself. But when the user uses a proxy server, the connection comes from the proxy, and it sends an HTTP header with information about the user's IP. – Barmar Jul 08 '16 at 23:33
  • Ah .. as you said, when the user uses a proxy like *(HotSpotSheild)*, then the connection comes from HSS, and it send an HTTP header with information about the user's IP. 1) which header exactly? 2) in this case `REMOTE_ADDR` is containing what thing? – Martin AJ Jul 08 '16 at 23:37
  • `REMOTE_ADDR` is the address of the proxy. I don't know what header HSS sends, probably one of the ones you listed. But like I said over and over, you can't trust headers sent from a proxy you don't control. – Barmar Jul 08 '16 at 23:38
  • Very well, according to your description, headers aren't safe at all. Also `REMOTE_ADDR` is the address of the proxy .. Well where is the real user's IP? I guess when a user uses the proxy, then he is undetectable. Am I right? – Martin AJ Jul 08 '16 at 23:41
  • The real user's IP is in one of those headers like `X-FORWARDED-FOR`. Unless the proxy doesn't send it, or sends a fake header, or the user is using a chain of proxies. That's why you can't trust the header if you don't manage the proxy, there's nothing forcing the proxy to put the correct information there. – Barmar Jul 08 '16 at 23:45
  • Totally I get that .. and yeah obviously the proxy doesn't put the correct information in the readers, that's its job. And my last question: *"if you don't manage the proxy"*, what do you mean "manage"? Should I do something? – Martin AJ Jul 08 '16 at 23:50
  • There's nothing you should do. Either it's a machine that you run, so you know that it provides valid information, or it's out of your control and you can't trust it. For instance, if you have your own load balancer, you manage it and you can believe its `X-FORWARDED-FOR` headers. But if someone is coming from a public proxy server, it's out of your purview. – Barmar Jul 09 '16 at 03:22
0

I think there is already a very good answer for this question on stackoverflow so i wouldn't elaborate which value to chose. See https://stackoverflow.com/a/15699240/6543678

I would note two things about logging user ip address.

First of all you should use some nosql database for this task. You might configure it as log backend and simple call something like \Log::info("{$ip} login as {$email}", \Log::GROUP_IP) or something similar what will be easy to use and later search in db for you.

On the other hand logging ip doesn't help at all from my point of view. Implement good strategies to avoid robots (e.g. google captcha), ban account's of aggressive users. Real hackers know how to hide their ip's. It's easy to use good proxy, you can use hacked personal computers/servers, use tor or many other ways to hide your identity.

Just don't waste too much time on the logging ip's in case your real goal is to secure your site.

Community
  • 1
  • 1