PHP bir kullanıcının doğru IP adresini almak için en doğru yolu nedir?

9 Cevap php

Ben IP adresi alımı için kullanılabilir $_SERVER değişkenleri başlıkları bir bolluk vardır biliyorum. En doğru kullanarak bir kullanıcının gerçek IP adresini (de hiçbir yöntem idealdir bilerek) almak için nasıl bir genel bir fikir birliği olup olmadığını merak ediyorum değişkenler dedi?

Ben derinlik çözüm bir bulmaya çalışırken biraz zaman geçirdim ve kaynaklardan sayısına göre aşağıdaki kod ile geldi. Biri cevap gedikler ya da belki daha doğru bir şey üzerinde biraz ışık tutacak lütfen eğer ben isterim.

edit includes optimizations from @Alix

 /**
  * Retrieves the best guess of the client's actual IP address.
  * Takes into account numerous HTTP proxy headers due to variations
  * in how different ISPs handle IP addresses in headers between hops.
  */
 public function get_ip_address() {
  // Check for shared internet/ISP IP
  if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
   return $_SERVER['HTTP_CLIENT_IP'];

  // Check for IPs passing through proxies
  if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
   // Check if multiple IP addresses exist in var
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    foreach ($iplist as $ip) {
     if ($this->validate_ip($ip))
      return $ip;
    }
   }
  }
  if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
   return $_SERVER['HTTP_X_FORWARDED'];
  if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
   return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
  if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
   return $_SERVER['HTTP_FORWARDED_FOR'];
  if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
   return $_SERVER['HTTP_FORWARDED'];

  // Return unreliable IP address since all else failed
  return $_SERVER['REMOTE_ADDR'];
 }

 /**
  * Ensures an IP address is both a valid IP address and does not fall within
  * a private network range.
  *
  * @access public
  * @param string $ip
  */
 public function validate_ip($ip) {
     if (filter_var($ip, FILTER_VALIDATE_IP, 
                         FILTER_FLAG_IPV4 | 
                         FILTER_FLAG_IPV6 |
                         FILTER_FLAG_NO_PRIV_RANGE | 
                         FILTER_FLAG_NO_RES_RANGE) === false)
         return false;
     self::$ip = $ip;
     return true;
 }

Words of Warning (update)

REMOTE_ADDR hala bir IP adresi most reliable kaynağı temsil eder. Burada bahsedilen diğer $_SERVER değişkenleri çok kolay bir uzak istemci tarafından taklit edilebilir. Bu çözümün amacı, bir proxy arkasında oturan bir müşterinin IP adresini belirlemek için teşebbüs etmektir. IP adresi $_SERVER['REMOTE_ADDR'] doğrudan döndü ve hem de depolama ile genel amaçlar için, birlikte bu kullanmayı düşünebilirsiniz.

For 99.9% of users this solution will suit your needs perfectly. Bu, kendi istek başlıklarını enjekte ederek sisteminizi kötüye isteyen kötü niyetli kullanıcıların% 0.1 'den sizi korumaz. REMOTE_ADDR şey misyon kritik, tatil için IP adresleri güvenerek ve bir proxy arkasında olanlar ikram rahatsız etmezseniz.

9 Cevap

Here is a shorter, cleaner way to get the IP address:

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;
                }
            }
        }
    }
}

Ben yardımcı olur umarım!


Sizin kod zaten oldukça tamamlanmış gibi görünüyor, ben (bir kenara zamanki IP uyarılar itibaren) içinde herhangi bir olası hata göremiyorum, olsa filtre uzantısı güvenmek validate_ip() işlevini değiştirmek istiyorsunuz:

public function validate_ip($ip)
{
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false)
    {
        return false;
    }

    self::$ip = sprintf('%u', ip2long($ip)); // you seem to want this

    return true;
}

Ayrıca HTTP_X_FORWARDED_FOR pasajı bundan basitleştirilmiş olabilir:

// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    // check if multiple ips exist in var
    if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false)
    {
        $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);

        foreach ($iplist as $ip)
        {
            if ($this->validate_ip($ip))
                return $ip;
        }
    }

    else
    {
        if ($this->validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
}

Buna:

// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);

    foreach ($iplist as $ip)
    {
        if ($this->validate_ip($ip))
            return $ip;
    }
}

Ayrıca IPv6 adreslerini doğrulamak isteyebilirsiniz.

O zaman bile, ancak bir kullanıcının gerçek IP adresi güvenilmez olacak alıyorum. Yapmaları gereken tek şey bir anonim proxy sunucusu (http_x_forwarded_for, http_forwarded için başlıklarını onur vermez bir, vb) kullanın ve aldığınız tüm proxy sunucusunun IP adresidir.

Anonim proxy sunucusu IP adreslerinin bir listesi varsa o zaman görebilirsiniz, ama bu da% 100 doğru olduğunu ve bunu yaparım çoğu, bir proxy sunucusu bildirin emin olmak için bir yolu yoktur. Birisi zekice ediliyor ve eğer, bunlar HTTP forvet için başlıklarını parodi edebilirsiniz.

Diyelim ki yerel üniversite sevmiyorum diyelim. Ben HTTP öne onur anlamaya çünkü IP onlar kayıtlı ve IP adresi, kötü şeyler yaparak sitenizde yasak olsun adresleri anlamaya. Liste sonsuzdur.

Sonra tahmin olarak, böyle bir üniversite ağı gibi iç IP adresleri önce metioned vardır. Bir çok 10.x.x.x biçimi kullanın. Yani bilemez tüm paylaşılan bir ağ için iletilen olmasıdır.

Sonra içine kadar başlamaz, ama dinamik IP adresleri artık genişbant yoludur. Yani. En uzun, 3 ay - bir kullanıcının IP adresi almak bile, bu 2 değişiklik bekliyoruz.

Büyük soru ne amaçla olduğunu?

Kodunuz olabilir yaklaşık olarak kapsamlı - ama bir proxy eklendi başlığı gibi göründüğünü nokta ise, YERİNE CLIENT_IP size denetim amaçları için bu bilgi istiyorum, ancak o zaman uyarı kullanan görüyoruz - onun çok kolay sahte.

Kesinlikle kimlik herhangi bir tür için IP adreslerini kullanmak asla - hatta bu sahte olabilir.

Bu nedenle şeffaf vekiller ya da vekil-enjekte başlıkları yanlış durumlarda ortaya koyacaktır olmayan bir http portu (yoluyla sunucuya geri bağlanan flash veya java uygulaması dışarı iterek istemci ip adresi daha iyi bir ölçüm alabilir - ancak nerede müşteri SADECE web proxy veya giden port bloke edilir üzerinden bağlayabilirsiniz, aklınızda, uygulaması hiçbir bağlantısı yok olacaktır.

C.

Biz kullanın:

/**
 * Get the customer's IP address.
 *
 * @return string
 */
public function getIpAddress() {
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    } else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        return trim($ips[count($ips) - 1]);
    } else {
        return $_SERVER['REMOTE_ADDR'];
    }
}

HTTP_X_FORWARDED_FOR patlayabilir çünkü Squid kullanıldığında IP adreslerini tespit etmişti garip konulardan biridir.

Cevap sadece bir VB.NET version:

Private Function GetRequestIpAddress() As IPAddress
    Dim serverVariables = HttpContext.Current.Request.ServerVariables
    Dim headersKeysToCheck = {"HTTP_CLIENT_IP", _
                              "HTTP_X_FORWARDED_FOR", _
                              "HTTP_X_FORWARDED", _
                              "HTTP_X_CLUSTER_CLIENT_IP", _
                              "HTTP_FORWARDED_FOR", _
                              "HTTP_FORWARDED", _
                              "REMOTE_ADDR"}
    For Each thisHeaderKey In headersKeysToCheck
        Dim thisValue = serverVariables.Item(thisHeaderKey)
        If thisValue IsNot Nothing Then
            Dim validAddress As IPAddress = Nothing
            If IPAddress.TryParse(thisValue, validAddress) Then
                Return validAddress
            End If
        End If
    Next
    Return Nothing
End Function

Belki de tersten patladı HTTP_X_FORWARDED_FOR üzerinde yineleme gerekir eğer benim deneyim kullanıcının IP adresi yani başlığının başında başlayarak, virgülle ayrılmış liste sonunda biter bu olmuştur beri ben, merak ediyorum, sen hala potansiyel olarak oturum kaçırma gibi birçok kullanıcı bu vekil aracılığıyla gelebilir izin verebilir döndü yakınlık birinin ip adresini almak için daha olasıdır.

Bunun için teşekkürler, çok yararlı.

Kodu doğru olsaydı bu olsa yardımcı olacaktır. Olduğu gibi ben korkuyorum aracı kimse aslında bunu denedim ben. Hangi hattı 20 civarında bir {çok var.

Ben deli olabilir, ancak birkaç geçerli ve geçersiz adresleri üzerinde denedikten sonra, çalışmış validate_ip tek sürümü () bu idi:

    public function validate_ip($ip)
    {
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) === false)
            return false;
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) === false)
            return false;
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false)
            return false;

        return true;
    }

Eğer CloudFlare önbelleğe tabaka Hizmetleri'ni kullanırsanız burada değiştirilmiş bir versiyonu bulunuyor

function getIP()
{
    $fields = array('HTTP_X_FORWARDED_FOR',
                    'REMOTE_ADDR',
                    'HTTP_CF_CONNECTING_IP',
                    'HTTP_X_CLUSTER_CLIENT_IP');

    foreach($fields as $f)
    {
        $tries = $_SERVER[$f];
        if (empty($tries))
            continue;
        $tries = explode(',',$tries);
        foreach($tries as $try)
        {
            $r = filter_var($try,
                            FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 |
                            FILTER_FLAG_NO_PRIV_RANGE |
                            FILTER_FLAG_NO_RES_RANGE);

            if ($r !== false)
            {
                return $try;
            }
        }
    }
    return false;
}

Hemen hemen kendi sorusunu yanıtladı! :)

function getRealIpAddr() {
    if(!empty($_SERVER['HTTP_CLIENT_IP']))   //Check IP address from shared Internet
    {
        $IPaddress = $_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //To check IP address is passed from the proxy
    {
        $IPaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else
    {
        $IPaddress = $_SERVER['REMOTE_ADDR'];
    }
    return $IPaddress;
}

Source