Jump to content

IP address - So what's the latest way of obtaining (with PHP only)


toplay

Recommended Posts

The various $_SERVER values listed below are some of the ones I've seen used to try and determine when a user is coming through a proxy and getting at the real web users IP address when available.

I'm hoping this post will help us once and for all (at this time anyway) come to some sort of concensus regarding the best approach to grabbing the IP address with PHP.

The code listed below are just examples I found and not necessarily correct (if there is such a thing as a one method approach when it comes to this). The example code don't check all the $_SERVER values I have listed (that's not to say that they all should be used or relevant).

I'm under the impression:

[list]
[*]That the 'HTTP_VIA' usually contains a proxies name and not necessarily the proxy IP address.
[*]The 'HTTP_X_FORWARDED_FOR', when populated, could contain multiple IP addresses separated with commas, and the last one in the list (not the first) would be considered the originating user's IP.
[*]A proxy may not necessarily populate any of the proxy related values (i.e. anonymous proxy).
[/list]

What do you use?
What do you think is the correct order of checking these $_SERVER values is (before finally resorting to using the 'REMOTE_ADDR')?

Do you know more than these values (as it relates to detecting proxy and obtaining IP address)?
[QUOTE]
$_SERVER['HTTP_VIA']
$_SERVER['HTTP_USER_AGENT_VIA']
$_SERVER['HTTP_COMING_FROM']   
$_SERVER['HTTP_X_COMING_FROM']
$_SERVER['HTTP_X_FORWARDED_FOR']
$_SERVER['HTTP_X_FORWARDED']
$_SERVER['HTTP_FORWARDED']
$_SERVER['HTTP_CLIENT_IP']
$_SERVER['HTTP_FROM']
$_SERVER['HTTP_PROXY_CONNECTION']
$_SERVER['HTTP_XROXY_CONNECTION']
$_SERVER['HTTP_PROXY_AUTHORIZATION']
$_SERVER['REMOTE_ADDR']
[/quote]

Example source:

[code=php:0]
function PMA_getIp()
{
    global $REMOTE_ADDR;
    global $HTTP_X_FORWARDED_FOR, $HTTP_X_FORWARDED, $HTTP_FORWARDED_FOR, $HTTP_FORWARDED;
    global $HTTP_VIA, $HTTP_X_COMING_FROM, $HTTP_COMING_FROM;

    // Get some server/environment variables values
    if (empty($REMOTE_ADDR)) {
        if (!empty($_SERVER) && isset($_SERVER['REMOTE_ADDR'])) {
            $REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
        }
        else if (!empty($_ENV) && isset($_ENV['REMOTE_ADDR'])) {
            $REMOTE_ADDR = $_ENV['REMOTE_ADDR'];
        }
        else if (@getenv('REMOTE_ADDR')) {
            $REMOTE_ADDR = getenv('REMOTE_ADDR');
        }
    } // end if
    if (empty($HTTP_X_FORWARDED_FOR)) {
        if (!empty($_SERVER) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $HTTP_X_FORWARDED_FOR = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        else if (!empty($_ENV) && isset($_ENV['HTTP_X_FORWARDED_FOR'])) {
            $HTTP_X_FORWARDED_FOR = $_ENV['HTTP_X_FORWARDED_FOR'];
        }
        else if (@getenv('HTTP_X_FORWARDED_FOR')) {
            $HTTP_X_FORWARDED_FOR = getenv('HTTP_X_FORWARDED_FOR');
        }
    } // end if
    if (empty($HTTP_X_FORWARDED)) {
        if (!empty($_SERVER) && isset($_SERVER['HTTP_X_FORWARDED'])) {
            $HTTP_X_FORWARDED = $_SERVER['HTTP_X_FORWARDED'];
        }
        else if (!empty($_ENV) && isset($_ENV['HTTP_X_FORWARDED'])) {
            $HTTP_X_FORWARDED = $_ENV['HTTP_X_FORWARDED'];
        }
        else if (@getenv('HTTP_X_FORWARDED')) {
            $HTTP_X_FORWARDED = getenv('HTTP_X_FORWARDED');
        }
    } // end if
    if (empty($HTTP_FORWARDED_FOR)) {
        if (!empty($_SERVER) && isset($_SERVER['HTTP_FORWARDED_FOR'])) {
            $HTTP_FORWARDED_FOR = $_SERVER['HTTP_FORWARDED_FOR'];
        }
        else if (!empty($_ENV) && isset($_ENV['HTTP_FORWARDED_FOR'])) {
            $HTTP_FORWARDED_FOR = $_ENV['HTTP_FORWARDED_FOR'];
        }
        else if (@getenv('HTTP_FORWARDED_FOR')) {
            $HTTP_FORWARDED_FOR = getenv('HTTP_FORWARDED_FOR');
        }
    } // end if
    if (empty($HTTP_FORWARDED)) {
        if (!empty($_SERVER) && isset($_SERVER['HTTP_FORWARDED'])) {
            $HTTP_FORWARDED = $_SERVER['HTTP_FORWARDED'];
        }
        else if (!empty($_ENV) && isset($_ENV['HTTP_FORWARDED'])) {
            $HTTP_FORWARDED = $_ENV['HTTP_FORWARDED'];
        }
        else if (@getenv('HTTP_FORWARDED')) {
            $HTTP_FORWARDED = getenv('HTTP_FORWARDED');
        }
    } // end if
    if (empty($HTTP_VIA)) {
        if (!empty($_SERVER) && isset($_SERVER['HTTP_VIA'])) {
            $HTTP_VIA = $_SERVER['HTTP_VIA'];
        }
        else if (!empty($_ENV) && isset($_ENV['HTTP_VIA'])) {
            $HTTP_VIA = $_ENV['HTTP_VIA'];
        }
        else if (@getenv('HTTP_VIA')) {
            $HTTP_VIA = getenv('HTTP_VIA');
        }
    } // end if
    if (empty($HTTP_X_COMING_FROM)) {
        if (!empty($_SERVER) && isset($_SERVER['HTTP_X_COMING_FROM'])) {
            $HTTP_X_COMING_FROM = $_SERVER['HTTP_X_COMING_FROM'];
        }
        else if (!empty($_ENV) && isset($_ENV['HTTP_X_COMING_FROM'])) {
            $HTTP_X_COMING_FROM = $_ENV['HTTP_X_COMING_FROM'];
        }
        else if (@getenv('HTTP_X_COMING_FROM')) {
            $HTTP_X_COMING_FROM = getenv('HTTP_X_COMING_FROM');
        }
    } // end if
    if (empty($HTTP_COMING_FROM)) {
        if (!empty($_SERVER) && isset($_SERVER['HTTP_COMING_FROM'])) {
            $HTTP_COMING_FROM = $_SERVER['HTTP_COMING_FROM'];
        }
        else if (!empty($_ENV) && isset($_ENV['HTTP_COMING_FROM'])) {
            $HTTP_COMING_FROM = $_ENV['HTTP_COMING_FROM'];
        }
        else if (@getenv('HTTP_COMING_FROM')) {
            $HTTP_COMING_FROM = getenv('HTTP_COMING_FROM');
        }
    } // end if

    // Gets the default ip sent by the user
    if (!empty($REMOTE_ADDR)) {
        $direct_ip = $REMOTE_ADDR;
    }

    // Gets the proxy ip sent by the user
    $proxy_ip    = '';
    if (!empty($HTTP_X_FORWARDED_FOR)) {
        $proxy_ip = $HTTP_X_FORWARDED_FOR;
    } else if (!empty($HTTP_X_FORWARDED)) {
        $proxy_ip = $HTTP_X_FORWARDED;
    } else if (!empty($HTTP_FORWARDED_FOR)) {
        $proxy_ip = $HTTP_FORWARDED_FOR;
    } else if (!empty($HTTP_FORWARDED)) {
        $proxy_ip = $HTTP_FORWARDED;
    } else if (!empty($HTTP_VIA)) {
        $proxy_ip = $HTTP_VIA;
    } else if (!empty($HTTP_X_COMING_FROM)) {
        $proxy_ip = $HTTP_X_COMING_FROM;
    } else if (!empty($HTTP_COMING_FROM)) {
        $proxy_ip = $HTTP_COMING_FROM;
    } // end if... else if...

    // Returns the true IP if it has been found, else FALSE
    if (empty($proxy_ip)) {
        // True IP without proxy
        return $direct_ip;
    } else {
        $is_ip = preg_match('|^([0-9]{1,3}\.){3,3}[0-9]{1,3}|', $proxy_ip, $regs = array());
        if ($is_ip && (count($regs) > 0)) {
            // True IP behind a proxy
            return $regs[0];
        } else {
            // Can't define IP: there is a proxy but we don't have
            // information about the true IP
            return FALSE;
        }
    } // end if... else...
} // end of the 'PMA_getIp()' function
[/code]




Another example:

[code=php:0]

function retrieveIP() {

function extractIP(&$ip) {
        if (ereg ("^([0-9]{1,3}\.){3,3}[0-9]{1,3}", $ip, $array))
                return $array;
        else
                return false;
}

function get_IP() {
        if(@$_SERVER['REMOTE_HOST']) {
                $array = extractIP(&$_SERVER['REMOTE_HOST']);
                if ($array && count($array) >= 1)
                        return $array[0]; // first IP in the list
        }
        return $_SERVER['REMOTE_ADDR'];
}

/*--------------------------------------------------
  get_real_IP()
  get the real IP if hidden by proxy
  --------------------------------------------------*/
function get_real_IP() {

        if(@$_SERVER['HTTP_X_FORWARDED_FOR']) { // case 1.A: proxy && HTTP_X_FORWARDED_FOR is defined
                $array = extractIP(&$_SERVER['HTTP_X_FORWARDED_FOR']);
                if ($array && count($array) >= 1) {
                        return $array[0]; // first IP in the list
                }
        }
        if(@$_SERVER['HTTP_X_FORWARDED']) { // case 1.B: proxy && HTTP_X_FORWARDED is defined
                $array = extractIP(&$_SERVER['HTTP_X_FORWARDED']);
                if ($array && count($array) >= 1) {
                        return $array[0]; // first IP in the list
                }
        }
        if(@$_SERVER['HTTP_FORWARDED_FOR']) { // case 1.C: proxy && HTTP_FORWARDED_FOR is defined
                $array = extractIP(&$_SERVER['HTTP_FORWARDED_FOR']);
                if ($array && count($array) >= 1) {
                        return $array[0]; // first IP in the list
                }
        }
        if(@$_SERVER['HTTP_FORWARDED']) { // case 1.D: proxy && HTTP_FORWARDED is defined
                $array = extractIP(&$_SERVER['HTTP_FORWARDED']);
                if ($array && count($array) >= 1) {
                        return $array[0]; // first IP in the list
                }
        }
        if(@$_SERVER['HTTP_CLIENT_IP']) { // case 1.E: proxy && HTTP_CLIENT_IP is defined
                $array = extractIP(&$_SERVER['HTTP_CLIENT_IP']);
                if ($array && count($array) >= 1) {
                        return $array[0]; // first IP in the list
                }
        }
       
        if(@$_SERVER['HTTP_VIA']) {
        // case 2:
        // proxy && HTTP_(X_) FORWARDED (_FOR) not defined && HTTP_VIA defined
        // other exotic variables may be defined
        return ( $_SERVER['HTTP_VIA'].
            '_' . $_SERVER['HTTP_X_COMING_FROM'].
            '_' . $_SERVER['HTTP_COMING_FROM']
          ) ;
        }
        if(@$_SERVER['HTTP_X_COMING_FROM'] || $_SERVER['HTTP_COMING_FROM'] ) {
        // case 3: proxy && only exotic variables defined
        // the exotic variables are not enough, we add the REMOTE_ADDR of the proxy
        return ( $_SERVER['REMOTE_ADDR'] .
            '_' . $_SERVER['HTTP_X_COMING_FROM'] .
            '_' . $_SERVER['HTTP_COMING_FROM']
          ) ;
        }
       
        // case 4: no proxy (or tricky case: proxy+refresh)
        if(@$_SERVER['REMOTE_HOST']) {
                $array = extractIP(&$_SERVER['REMOTE_HOST']);
                if ($array && count($array) >= 1) {
                        return $array[0]; // first IP in the list
                }
        }

        return $_SERVER['REMOTE_ADDR'];
}

if(isset($_SERVER['HTTP_VIA']) && $_SERVER['HTTP_VIA'])  // Using proxy!
        return get_real_IP();
else // Not using proxy...
        return (get_IP()) ? get_IP() : get_real_IP();
}

?>
[/code]


EDIT:

We could PIN this topic later if people want.
Link to comment
Share on other sites

Thanks for your replies. I don't want this post to be about faked/spoofed stuff. That's known and has been discussed to death.

A person should always record the 'REMOTE_ADDR'. But assuming everything is on the up and up, the user's real IP address is not that (when coming through a proxy).

For this discussion, we're talking about legitimate users coming through various proxies.



Link to comment
Share on other sites

Because most are not forged.

I don't see the point of [b]only[/b] keeping the 'REMOTE_ADDR' (which maybe a proxy IP) when it may not trace back to the user.

If the user keeps coming from different proxy IP's, and sometimes you can grab what seems their real IP, then it's a way of possibly matching and tracing back to the same user.
Link to comment
Share on other sites

Let's say you save everything, then how do you know which is the user's real IP address? I don't understand the point of saving everything if one doesn't understand what it means or how to use the data. Also, saving everything is impractical and when you have a large user base takes up a lot of disk space (especially if your tables use UTF-8).

Does anyone else have something to say directly relating to the correct order of checking these $_SERVER values?

Link to comment
Share on other sites

$_SERVER variables are never the same on all servers, so you need to limit what works across all servers, if you don't you will end up with a order that will never work on all servers. So you will end up giving less information or worse, no useful information at all. All $_SERVER variables not related to internal pathing can be forged, so why would you even spend that much time on something that has no real value. What I mean is, locks on doors only keep honest people honest, the bad people don't every think about the lock. So all your testing is a very silly waste of time!

Sonia
Link to comment
Share on other sites

Sonia - printf,

I for one will be really happy to know if i could ban people using fake ips from sending junk info on my contact form. Its contact.php and i get tons of people writing fake email ids (ab@y.com) and for name and address, stuff like 123, 456 etc. So if an ip is fake or a spybot, i want them to hit the submit button (do all their stupid work) and then get a popup saying " your data wont be accepted becoz your ip address is a fake" .

i'm eager to see how this post will go forward !

Link to comment
Share on other sites

swatisonee,

One can't tell if it's a fake IP necessarily, but could see if it's on a black list.

There are services like the ones I've listed below, that help you determine various components for yourself, and is especially helpful if you accept credit card orders (which should help to reduce chargebacks).

FYI:

Fraud screen services:
http://www.maxmind.com/app/ccv
http://fraudlabs.com/fraudlabs.aspx##input
http://www.cybersource.com/products_and_services/credit_card_fraud_management/fraud_screening/
http://precharge.com/global_fraud_screening/  (returns just a fraud score)
http://www.orderspy.com
http://www.serviceobjects.com/Products/default.asp
http://www.modernbill.com/order-verification/howitworks.php
http://www.nehuenmultimedia.com.ar/html/cardverify.php  (free online check 10 a day)
http://www.algozone.com/shop/oscommerce_fraud_protection.php

Other stuff:

Free IP to Country Database:
http://software77.net/cgi-bin/ip-country/geo-ip.pl

First six digits of credit card # (BIN) online lookup (free limited):
http://all-nettools.com/toolbox,financial

Merchants helping other merchants by way of newsletter/email. Notification to each other about bad IP's and orders (with parts of credit card number listed):
http://merchant911.org

IP blacklist:
http://www.unixhub.com/block.html

The SBL is a realtime database of IP addresses of verified spam sources:
http://www.spamhaus.org/sbl/

Lookup of known and potential spam sources (open relays, open proxies, open form to mail HTTP gateways, dynamic IP pools, and direct spammers):
http://www.njabl.org/

IP lookups:
http://www.ipaddressguide.com/
http://www.dnsstuff.com/
http://www.geobytes.com/IpLocator.htm?GetLocation
Link to comment
Share on other sites

[quote author=Jenk link=topic=114669.msg466923#msg466923 date=1163356158]
IP addresses are so unreliable it terms of security, that _any_ time spent on them is wasted time.

Don't bother even logigng IP's, there really is no point.
[/quote]
I disagree with you. It's helped us evaluate and close fraudulent accounts.
Link to comment
Share on other sites

[quote author=toplay link=topic=114669.msg466886#msg466886 date=1163348289]Does anyone else have something to say directly relating to the correct order of checking these $_SERVER values?[/quote]
That's what I'm saying, there simply is no correct order. All of the values can forged equally easily, it doesn't really matter what order you put the data in if it isn't trustworthy data to start with (a garbage in-garbage out kind of thing.)
Link to comment
Share on other sites

[quote author=brendandonhue link=topic=114669.msg467067#msg467067 date=1163382745]
[quote author=toplay link=topic=114669.msg466886#msg466886 date=1163348289]Does anyone else have something to say directly relating to the correct order of checking these $_SERVER values?[/quote]
That's what I'm saying, there simply is no correct order. All of the values can forged equally easily, it doesn't really matter what order you put the data in if it isn't trustworthy data to start with (a garbage in-garbage out kind of thing.)
[/quote]

So many negative one minded people.

Firstly there are far more users who know how to use a proxy and do so on a regular basis than there are people who know how to manually append headers to every request that they make. So even for security this is a solution that aims to cover a large group of people, while still realizing that the data can't be trusted in some cases.

Second, this may be used for something which isn't related to security at all. It could just be used to tell approximatly how many unique users a site is getting. Sure there could be people faking it, but the majority wouldn't so it would give you a more accurate result than just relying on users not being behind a proxy.

Thanks for your work and research on this topic toplay, it has helped me a great deal. I wish I could help you out with the order, but unfortunatly I have no idea. I suspect the best way to find out would be to to find out what the biggest commercial proxy server products usually send etc.

Luck
Link to comment
Share on other sites

[quote author=toplay link=topic=114669.msg466615#msg466615 date=1163282701]
[list]
[*]The 'HTTP_X_FORWARDED_FOR', when populated, could contain multiple IP addresses separated with commas, and the last one in the list (not the first) would be considered the originating user's IP.
[/list]
...
[code=php:0]
|^([0-9]{1,3}\.){3,3}[0-9]{1,3}|
[/code]
[/quote]

Huh.. these two things seem to contradict each other.

Shouldn't the pattern be the following?
|([0-9]{1,3}\.){3,3}[0-9]{1,3}$|
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.