PHP में उपयोगकर्ता के सही IP पते को पुनः प्राप्त करने का सबसे सटीक तरीका क्या है?


301

मुझे पता है कि IP पता पुनर्प्राप्ति के लिए $ _SERVER चर शीर्ष लेख उपलब्ध हैं। मैं सोच रहा था कि क्या कोई आम सहमति है कि किसी उपयोगकर्ता के वास्तविक आईपी पते को ठीक से कैसे प्राप्त किया जाए (अच्छी तरह से कोई भी विधि सही नहीं है) कहा चर का उपयोग कर?

मैंने कुछ समय गहराई से हल खोजने की कोशिश में बिताया और कई स्रोतों के आधार पर निम्नलिखित कोड के साथ आया। मुझे यह अच्छा लगेगा अगर कोई उत्तर में छेद को दबा सकता है या शायद कुछ और सटीक पर कुछ प्रकाश डाल सकता है।

संपादित करें में @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;
 }

चेतावनी के शब्द (अद्यतन)

REMOTE_ADDRअभी भी एक आईपी पते के सबसे विश्वसनीय स्रोत का प्रतिनिधित्व करता है । अन्य$_SERVERयहां उल्लिखित चर किसी दूरस्थ ग्राहक द्वारा बहुत आसानी से खराब किए जा सकते हैं। इस समाधान का उद्देश्य प्रॉक्सी के पीछे बैठे क्लाइंट के आईपी पते को निर्धारित करने का प्रयास करना है। अपने सामान्य उद्देश्यों के लिए, आप सीधे आईपी पते के साथ संयोजन में इसका उपयोग करने पर विचार कर सकते हैं $_SERVER['REMOTE_ADDR']और दोनों को संग्रहीत कर सकते हैं।

99.9% उपयोगकर्ताओं के लिए यह समाधान आपकी आवश्यकताओं के अनुरूप होगा। यह आपके स्वयं के अनुरोध हेडर को इंजेक्ट करके आपके सिस्टम का दुरुपयोग करने वाले 0.1% दुर्भावनापूर्ण उपयोगकर्ताओं से आपकी रक्षा नहीं करेगा। यदि किसी मिशन के लिए IP पते पर निर्भर होना महत्वपूर्ण है, तो सहारा लें REMOTE_ADDRऔर प्रॉक्सी के पीछे उन लोगों के खानपान को परेशान न करें।


2
Whatismyip.com प्रश्न के लिए, मैं सोच रहा हूं कि वे इस स्क्रिप्ट की तरह कुछ कर रहे हैं, क्या आप इसे स्थानीय स्तर पर चला रहे हैं? यदि आपके पास आंतरिक आईपी है, तो उस स्थिति में सार्वजनिक इंटरफ़ेस पर कुछ भी नहीं भेजा जा रहा है, इसलिए php को प्राप्त करने के लिए कोई जानकारी नहीं है
मैट

2
यह सुनिश्चित करें कि इसे लागू करते समय आप इसे ध्यान में रखें: stackoverflow.com/questions/1672827/…
केविन पेनो

19
याद रखें कि इन सभी HTTP हेडर को संशोधित करना वास्तव में आसान है: आपके समाधान के साथ, मुझे बस एक यादृच्छिक आईपी के साथ एक्स-फॉरवर्ड-फॉर हेडर भेजने के लिए अपने ब्राउज़र को कॉन्फ़िगर करना होगा और आपकी स्क्रिप्ट खुशी से एक नकली पता लौटाएगी। इसलिए आप जो करने की कोशिश कर रहे हैं उसके आधार पर, यह समाधान केवल REMOTE_ADDR के उपयोग से कम विश्वसनीय हो सकता है।
सूक्ति

14
OMFG, "अविश्वसनीय आईपी"! मैं पहली बार एसओ पर इस तरह की बकवास देख रहा हूं। एकमात्र विश्वसनीय IP पता REMOTE_ADDR है
आपका कॉमन सेंस

3
-1 यह स्पूफिंग के लिए कमजोर है। आप जो कुछ भी कर रहे हैं वह उपयोगकर्ता से पूछ रहा है कि उसका आईपी पता क्या होना चाहिए।
किश्ती

जवाबों:


268

यहां IP पता प्राप्त करने का एक छोटा, साफ-सुथरा तरीका है:

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

मुझे उम्मीद है यह मदद करेगा!


आपका कोड पहले से ही बहुत अच्छा लग रहा है, मैं इसमें किसी भी संभावित कीड़े को नहीं देख सकता (सामान्य आईपी कैविट्स से अलग), मैं validate_ip()फ़िल्टर एक्सटेंशन पर भरोसा करने के लिए फ़ंक्शन को बदलूंगा:

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

इसके अलावा आपके HTTP_X_FORWARDED_FORस्निपेट को इससे सरल बनाया जा सकता है:

// 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'];
    }
}

इसके लिए:

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

आप IPv6 पतों को मान्य करना चाह सकते हैं।


4
मैं निश्चित रूप से filter_varफिक्स की सराहना करता हूं क्योंकि यह आईपी पते पर हैकिश अहस्ताक्षरित इंट चेक का एक गुच्छा निकालता है। मुझे यह भी पसंद है कि यह मुझे आईपीवी 6 पतों को भी मान्य करने का विकल्प देता है। HTTP_X_FORWARDED_FORअनुकूलन भी बहुत सराहना कर रहा है। कुछ ही मिनटों में मैं कोड अपडेट कर दूंगा।
कोरी बलौ

33
-1 यह आपके द्वारा किए जा रहे सभी स्पूफिंग के लिए कमजोर है, उपयोगकर्ता से पूछ रहा है कि उसका आईपी पता क्या होना चाहिए।
किश्ती

7
@Rook: हाँ, मुझे पता है। ओपी इसके बारे में जानता है, और मैंने अपने उत्तर में भी इसका उल्लेख किया है। लेकिन टिप्पणी के लिए धन्यवाद।
एलिक्स एक्सल

1
FYI करें: मुझे Alix Axel का कोड काम करने के लिए FILTER_FLAG_IPV6 को निकालना पड़ा।
DarkAsPitch

2
@ rubenrp81 टीसीपी सॉकेट हैंडलर एकमात्र विहित स्रोत है, बाकी सब हमलावर-नियंत्रित है। उपरोक्त कोड एक हमलावर का सपना है।
किश्ती

12

फिर भी, उपयोगकर्ता का वास्तविक IP पता प्राप्त करना अविश्वसनीय होने वाला है। उन्हें बस इतना करने की जरूरत है कि एक गुमनाम प्रॉक्सी सर्वर का उपयोग किया जाए (एक जो http_x_forwarded_for, http_forwarded, आदि के लिए हेडर का सम्मान नहीं करता है) और आप सभी को उनके प्रॉक्सी सर्वर का आईपी पता मिलता है।

फिर आप देख सकते हैं कि क्या प्रॉक्सी सर्वर आईपी पतों की एक सूची है जो गुमनाम हैं, लेकिन यह सुनिश्चित करने का कोई तरीका नहीं है कि यह 100% सटीक है और सबसे अधिक यह आपको बताएगा कि यह प्रॉक्सी सर्वर है। और अगर कोई चालाक हो रहा है, तो वे HTTP फॉरवर्ड के लिए हेडर को खराब कर सकते हैं।

मान लीजिए कि मुझे स्थानीय कॉलेज पसंद नहीं है। मैं यह पता लगाता हूं कि उन्होंने क्या आईपी पते दर्ज किए हैं, और बुरा काम करके आपकी साइट पर अपना आईपी पता प्रतिबंधित कर दिया है, क्योंकि मुझे पता है कि आप HTTP फॉरवर्ड का सम्मान करते हैं। असीमित सूची है।

फिर, जैसा कि आपने अनुमान लगाया है, आंतरिक आईपी पते जैसे कि कॉलेज नेटवर्क जो मैंने पहले मिला था। बहुत सारे 10.xxx प्रारूप का उपयोग करते हैं। तो आप सभी को पता होगा कि यह एक साझा नेटवर्क के लिए भेजा गया था।

तब मैं इसमें ज्यादा शुरुआत नहीं करूंगा, लेकिन गतिशील आईपी पते अब ब्रॉडबैंड का रास्ता हैं। इसलिए। यहां तक ​​कि अगर आपको एक उपयोगकर्ता आईपी पता मिलता है, तो सबसे लंबे समय तक इसे 2 - 3 महीने में बदलने की उम्मीद करें।


इनपुट के लिए धन्यवाद। मैं वर्तमान में सत्र अपहरण को सीमित करने के लिए उनके वर्ग सी आईपी का उपयोग करके सत्र प्रमाणीकरण में सहायता के लिए उपयोगकर्ता के आईपी पते का उपयोग कर रहा हूं, लेकिन कारण के भीतर गतिशील आईपी के लिए अनुमति देता हूं। Spoofed IPs और अनाम प्रॉक्सी सर्वर सिर्फ एक ऐसी चीज़ है जिसके लिए मुझे कुछ चुनिंदा व्यक्तियों के समूह से निपटना होगा।
कोरी बल्लू

@cballou - निश्चित रूप से इस उद्देश्य के लिए REMOTE_ADDR उपयोग करने के लिए सही है। HTTP हेडर पर भरोसा करने वाला कोई भी तरीका हैडर स्पूफिंग के लिए कमजोर है। एक सत्र कब तक है? डायनेमिक आईपी तेजी से नहीं बदलते हैं।
एमजेडबी

वे करते हैं, खासकर अगर मैं उन्हें (मैक पते को बदलना जो कई ड्राइवर समर्थन करते हैं) चाहते हैं। बस REMOTE_ADDR अपने आप में यह जानने के लिए पर्याप्त है कि आखिरी सर्वर से क्या बात की गई थी। तो एक प्रॉक्सी स्थिति में आप प्रॉक्सी आईपी प्राप्त करते हैं।

8

हम प्रयोग करते हैं:

/**
 * 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 पर विस्फोट अजीब मुद्दों के कारण होता है जब हमने स्क्वीड का उपयोग किए जाने पर आईपी पते का पता लगाया था।


वूप्स, मुझे बस एहसास हुआ कि आप मूल रूप से विस्फोट के साथ एक ही बात करते हैं, और आगे। प्लस थोड़ा अतिरिक्त। इसलिए मुझे संदेह है कि मेरा उत्तर बहुत मददगार था। :)
गैब्रिएलक


3

मेरा उत्तर मूल रूप से सिर्फ एक पॉलिश, पूरी तरह से मान्य, और पूरी तरह से पैक किया गया, @ AlixAxel के उत्तर का संस्करण है:

<?php

/* Get the 'best known' client IP. */

if (!function_exists('getClientIP'))
    {
        function getClientIP()
            {
                if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) 
                    {
                        $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
                    };

                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)) 
                            {
                                foreach (explode(',', $_SERVER[$key]) as $ip)
                                    {
                                        $ip = trim($ip);

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

                return false;
            };
    };

$best_known_ip = getClientIP();

if(!empty($best_known_ip))
    {
        $ip = $clients_ip = $client_ip = $client_IP = $best_known_ip;
    }
else
    {
        $ip = $clients_ip = $client_ip = $client_IP = $best_known_ip = '';
    };

?>

परिवर्तन:

  • यह फ़ंक्शन नाम ('कैमलकेस' स्वरूपण शैली के साथ) को सरल करता है।

  • इसमें यह सुनिश्चित करने के लिए एक चेक शामिल है कि फ़ंक्शन आपके कोड के किसी अन्य भाग में पहले से ही घोषित नहीं है।

  • यह 'CloudFlare' संगतता को ध्यान में रखता है।

  • यह 'getClientIP' फ़ंक्शन के कई "आईपी-संबंधित" चर नामों को लौटाए गए मान से आरंभ करता है।

  • यह सुनिश्चित करता है कि यदि फ़ंक्शन एक वैध आईपी पता वापस नहीं करता है, तो सभी चर इसके बजाय एक खाली स्ट्रिंग पर सेट किए जाते हैं null

  • यह कोड की केवल (45) लाइनें हैं।


2

सबसे बड़ा सवाल किस उद्देश्य के लिए है?

आपका कोड लगभग उतना ही व्यापक हो सकता है जितना कि यह हो सकता है - लेकिन मैं देखता हूं कि यदि आप स्पॉट करते हैं तो प्रॉक्सी वर्धित हेडर जैसा दिखता है, तो आप CLIENT_IP के उस INSTEAD का उपयोग करते हैं, हालांकि यदि आप ऑडिट के उद्देश्यों के लिए यह जानकारी चाहते हैं तो चेतावनी दें - बहुत आसान ढोंग करना।

निश्चित रूप से आपको किसी भी तरह के प्रमाणीकरण के लिए कभी भी आईपी पते का उपयोग नहीं करना चाहिए - यहां तक ​​कि ये खराब हो सकते हैं।

आप एक फ्लैश या जावा एप्लेट को धक्का देकर क्लाइंट आईपी पते का बेहतर माप प्राप्त कर सकते हैं जो कि एक गैर-http पोर्ट के माध्यम से सर्वर से वापस जुड़ता है (जो इसलिए पारदर्शी परदे के पीछे या उन मामलों को प्रकट करेगा जहां प्रॉक्सी इंजेक्ट किए गए हेडर झूठे हैं - लेकिन यह ध्यान रखें कि, जहां ग्राहक केवल वेब प्रॉक्सी के माध्यम से कनेक्ट हो सकता है या आउटगोइंग पोर्ट ब्लॉक हो जाता है, एप्लेट से कोई कनेक्शन नहीं होगा।

सी।


ध्यान में रखते हुए मैं एक PHP केवल समाधान के लिए देख रहा हूं, क्या आप सुझाव दे रहे हैं कि मैं $_SERVER['CLIENT_IP']बयान के रूप में दूसरा जोड़ूं ?
कोरी बल्लू

नहीं - सिर्फ इतना है कि अगर आप लौटाए गए डेटा पर कोई महत्व देना चाहते हैं, तो यह नेटवर्क एंड पॉइंट एड्रेस (क्लाइंट आईपी) को संरक्षित करने के साथ-साथ प्रॉक्सी वर्धित हेडर में एक अलग मान का सुझाव देने वाले कुछ भी होगा (जैसे आप हो सकता है) 192.168.1.x पते के बहुत सारे देखें, लेकिन अलग-अलग ग्राहक ips से आ रहे हैं) C.
सिम्बियन

1

मुझे लगता है कि ऊपर बहुत बेहतर और अधिक संक्षिप्त उत्तर हैं, और यह एक फ़ंक्शन और न ही सबसे सुंदर स्क्रिप्ट के आसपास है। हमारे मामले में हमें स्पूफ़ेबल x_forwarded_for और अधिक विश्वसनीय Remote_addr दोनों को एक सादी स्विच-प्रति-आउटपुट में आउटपुट करने की आवश्यकता थी। इसे अन्य कार्यों में इंजेक्ट करने के लिए रिक्त स्थान की अनुमति देने की आवश्यकता थी, यदि कोई नहीं या यदि-एकवचन (केवल पूर्वनिर्मित फ़ंक्शन को वापस करने के बजाय)। इसे प्लेटफ़ॉर्म सेटिंग्स के लिए प्रति-स्विच अनुकूलित लेबल के साथ "चालू या बंद" संस्करण की आवश्यकता थी। यह भी अनुरोध के आधार पर $ ip के लिए गतिशील होने के लिए एक रास्ता चाहिए ताकि यह आगे अग्रेषित का रूप ले ले।

इसके अलावा, मैं किसी को भी पता नहीं देख पा रहा हूँ () बनाम रिक्त! ध्यान रखें कि आप x_forwarded_for के रूप में "PWNED" जैसे शब्दों को बिगाड़ सकते हैं, इसलिए सुनिश्चित करें कि आप एक वास्तविक आईपी सिंटैक्स को बाँझें अगर आपका आउटपुट कहीं संरक्षित है या डीबी में।

इसके अलावा, यदि आप x_forwarder_for में सरणी को देखने के लिए बहु-प्रॉक्सी की आवश्यकता है, तो आप Google अनुवाद का उपयोग करके परीक्षण कर सकते हैं। यदि आप परीक्षण करने के लिए हेडर स्पूफ करना चाहते हैं, तो क्रोम क्लाइंट हैडर स्पूफ एक्सटेंशन की जांच करें । यह अननोन प्रॉक्सी के पीछे केवल मानक Remote_addr के लिए डिफ़ॉल्ट होगा।

मुझे कोई भी मामला पता नहीं है, जहां Remote_addr खाली हो सकता है, लेकिन इसके मामले में अभी भी गिरावट है।

// proxybuster - attempts to un-hide originating IP if [reverse]proxy provides methods to do so
  $enableProxyBust = true;

if (($enableProxyBust == true) && (isset($_SERVER['REMOTE_ADDR'])) && (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) && (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))) {
    $ip = end(array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']))));
    $ipProxy = $_SERVER['REMOTE_ADDR'];
    $ipProxy_label = ' behind proxy ';
} elseif (($enableProxyBust == true) && (isset($_SERVER['REMOTE_ADDR']))) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $ipProxy = '';
    $ipProxy_label = ' no proxy ';
} elseif (($enableProxyBust == false) && (isset($_SERVER['REMOTE_ADDR']))) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $ipProxy = '';
    $ipProxy_label = '';
} else {
    $ip = '';
    $ipProxy = '';
    $ipProxy_label = '';
}

नीचे फ़ंक्शन (एस) या क्वेरी / इको / व्यू में उपयोग के लिए इनको गतिशील बनाने के लिए, लॉग जनरल या त्रुटि रिपोर्टिंग के लिए कहें, ग्लोबल्स या सिर्फ इको एमो का उपयोग करें जहां आप अन्य स्थितियों या स्थिर-स्कीमा-आउटपुट का एक टन बनाए बिना इच्छा करते हैं। कार्य करता है।

function fooNow() {
    global $ip, $ipProxy, $ipProxy_label;
    // begin this actions such as log, error, query, or report
}

आपके सभी महान विचारों के लिए धन्यवाद। कृपया मुझे बताएं कि क्या यह बेहतर हो सकता है, फिर भी इन हेडर के लिए थोड़े नए हैं :)


1

मैं इस फ़ंक्शन के साथ आया था जो केवल आईपी पते को वापस नहीं करता है, लेकिन आईपी जानकारी के साथ एक सरणी।

// Example usage:
$info = ip_info();
if ( $info->proxy ) {
    echo 'Your IP is ' . $info->ip;
} else {
    echo 'Your IP is ' . $info->ip . ' and your proxy is ' . $info->proxy_ip;
}

यहाँ समारोह है:

/**
 * 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.
 *
 * @since 1.1.3
 *
 * @return object {
 *         IP Address details
 *
 *         string $ip The users IP address (might be spoofed, if $proxy is true)
 *         bool $proxy True, if a proxy was detected
 *         string $proxy_id The proxy-server IP address
 * }
 */
function ip_info() {
    $result = (object) array(
        'ip' => $_SERVER['REMOTE_ADDR'],
        'proxy' => false,
        'proxy_ip' => '',
    );

    /*
     * This code tries to bypass a proxy and get the actual IP address of
     * the visitor behind the proxy.
     * Warning: These values might be spoofed!
     */
    $ip_fields = array(
        'HTTP_CLIENT_IP',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED',
        'HTTP_X_CLUSTER_CLIENT_IP',
        'HTTP_FORWARDED_FOR',
        'HTTP_FORWARDED',
        'REMOTE_ADDR',
    );
    foreach ( $ip_fields as $key ) {
        if ( array_key_exists( $key, $_SERVER ) === true ) {
            foreach ( explode( ',', $_SERVER[$key] ) as $ip ) {
                $ip = trim( $ip );

                if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
                    $forwarded = $ip;
                    break 2;
                }
            }
        }
    }

    // If we found a different IP address then REMOTE_ADDR then it's a proxy!
    if ( $forwarded != $result->ip ) {
        $result->proxy = true;
        $result->proxy_ip = $result->ip;
        $result->ip = $forwarded;
    }

    return $result;
}

1

जैसा कि किसी ने पहले कहा था, यहां कुंजी इस बात के लिए है कि आप किस कारण से उपयोगकर्ता के ips को स्टोर करना चाहते हैं।

मैं एक पंजीकरण प्रणाली से एक उदाहरण देता हूं जिस पर मैं काम करता हूं और निश्चित रूप से इस पुरानी चर्चा में sth का योगदान करने के लिए समाधान जो मेरी खोजों में अक्सर आता है।

कई php पंजीकरण पुस्तकालयों का उपयोग उपयोगकर्ता के आईपी पर आधारित विफल प्रयासों के लिए थ्रॉटल / लॉक आउट करने के लिए आईपी का उपयोग करता है। इस तालिका पर विचार करें:

-- mysql
DROP TABLE IF EXISTS `attempts`;
CREATE TABLE `attempts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` varchar(39) NOT NULL, /*<<=====*/
  `expiredate` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 -- sqlite
...

फिर, जब कोई उपयोगकर्ता पासवर्ड रीसेट करने की तरह सर्विसिंग से संबंधित लॉगिन या कुछ भी करने की कोशिश करता है, तो एक फ़ंक्शन को शुरू में बुलाया जाता है:

public function isBlocked() {
      /*
       * used one of the above methods to capture user's ip!!!
       */
      $ip = $this->ip;
      // delete attempts from this ip with 'expiredate' in the past
      $this->deleteAttempts($ip, false);
      $query = $this->dbh->prepare("SELECT count(*) FROM {$this->token->get('table_attempts')} WHERE ip = ?");
      $query->execute(array($ip));
      $attempts = $query->fetchColumn();
      if ($attempts < intval($this->token->get('attempts_before_verify'))) {
         return "allow";
      }
      if ($attempts < intval($this->token->get('attempts_before_ban'))) {
         return "captcha";
      }
      return "block";
   }

उदाहरण के लिए, कहो $this->token->get('attempts_before_ban') === 10और 2 उपयोगकर्ता एक ही ips के लिए आते हैं जैसा कि पिछले कोड में मामला है जहां हेडर को खराब किया जा सकता है , फिर 5 प्रयासों के बाद दोनों को प्रतिबंधित कर दिया जाता है ! इससे भी बदतर, अगर सभी एक ही प्रॉक्सी से आते हैं तो केवल पहले 10 उपयोगकर्ताओं को लॉग इन किया जाएगा और बाकी सभी को प्रतिबंधित कर दिया जाएगा!

यहां महत्वपूर्ण यह है कि हमें टेबल पर एक अद्वितीय सूचकांक की आवश्यकता है attemptsऔर हम इसे एक संयोजन से प्राप्त कर सकते हैं जैसे:

 `ip` varchar(39) NOT NULL,
 `jwt_load varchar(100) NOT NULL

जहाँ jwt_loadएक http कुकी आती है जो json वेब टोकन तकनीक का अनुसरण करती है जहाँ हम केवल एन्क्रिप्टेड पेलोड को संग्रहीत करते हैं जिसमें प्रत्येक उपयोगकर्ता के लिए एक मनमाना / अद्वितीय मान होना चाहिए । बेशक अनुरोध को संशोधित किया जाना चाहिए: "SELECT count(*) FROM {$this->token->get('table_attempts')} WHERE ip = ? AND jwt_load = ?"और वर्ग को भी पहल करनी चाहिए private $jwt


0

मुझे आश्चर्य है कि शायद आपको रिवर्स ऑर्डर में विस्फोटित HTTP_X_FORWARDED_FOR पर पुनरावृति करनी चाहिए, क्योंकि मेरा अनुभव यह रहा है कि उपयोगकर्ता का आईपी पता अल्पविराम से अलग की गई सूची के अंत में समाप्त होता है, इसलिए हेडर के शुरू होने पर, आप किसी एक प्रॉक्सी का आईपी पता प्राप्त करने की अधिक संभावना है, जो संभावित रूप से अभी भी सत्र को अपहरण करने की अनुमति दे सकता है क्योंकि कई उपयोगकर्ता उस प्रॉक्सी के बाद आ सकते हैं।


1
HTTP_X_FORWARDED_FOR: en.wikipedia.org/wiki/X-Forwarded-For पर विकिपीडिया पृष्ठ को पढ़ने के बाद ... मुझे लगता है कि सुझाया गया आदेश है, वास्तव में, आपके कोड के रूप में दाएं से बाएं। हालांकि, हमारे लॉग से मैं देख सकता हूं कि बहुत सारे मामले हैं जहां यह जंगली में परदे के पीछे का सम्मान नहीं है और आईपी पते जो आपकी जांच करना चाहते हैं वह सूची के दोनों छोर पर हो सकता है।
क्रिस विंटर

1
या बीच में, जैसा कि होगा अगर कुछ समीपवर्ती लोगों ने बाएं से दाएं क्रम का सम्मान किया और दूसरों ने नहीं किया।
ब्रिलियनड

0

इसके लिए धन्यवाद, बहुत उपयोगी है।

हालांकि यह मदद करेगा कि क्या कोड वाक्य रचना में सही थे। जैसा कि वहाँ है एक {बहुत बहुत लाइन 20 के आसपास। मुझे डर है कि इसका मतलब किसी ने वास्तव में इसे आज़माया नहीं है।

मैं पागल हो सकता हूं, लेकिन इसे कुछ वैध और अमान्य पतों पर आज़माने के बाद, वैद्य_िप () के एकमात्र संस्करण में काम किया गया था:

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

0

यदि आप CloudFlare कैशिंग परत सेवाओं का उपयोग करते हैं, तो यहां एक संशोधित संस्करण है

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

0

जवाब का सिर्फ एक VB.NET संस्करण:

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

3
प्रश्न में टैग "PHP" है
luchaninov

0

बस एक और साफ तरीका:

  function validateIp($var_ip){
    $ip = trim($var_ip);

    return (!empty($ip) &&
            $ip != '::1' &&
            $ip != '127.0.0.1' &&
            filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false)
            ? $ip : false;
  }

  function getClientIp() {
    $ip = @$this->validateIp($_SERVER['HTTP_CLIENT_IP']) ?:
          @$this->validateIp($_SERVER['HTTP_X_FORWARDED_FOR']) ?:
          @$this->validateIp($_SERVER['HTTP_X_FORWARDED']) ?:
          @$this->validateIp($_SERVER['HTTP_FORWARDED_FOR']) ?:
          @$this->validateIp($_SERVER['HTTP_FORWARDED']) ?:
          @$this->validateIp($_SERVER['REMOTE_ADDR']) ?:
          'LOCAL OR UNKNOWN ACCESS';

    return $ip;
  }

0

सिम्फनी के अनुरोध वर्ग https://github.com/symfony/symfony/blob/1bd125ec4a01220878b3dbc3ec3156b073996af9/src/Symfony/Component/HttpFoundation/Request.phpp से

const HEADER_FORWARDED = 'forwarded';
const HEADER_CLIENT_IP = 'client_ip';
const HEADER_CLIENT_HOST = 'client_host';
const HEADER_CLIENT_PROTO = 'client_proto';
const HEADER_CLIENT_PORT = 'client_port';

/**
 * Names for headers that can be trusted when
 * using trusted proxies.
 *
 * The FORWARDED header is the standard as of rfc7239.
 *
 * The other headers are non-standard, but widely used
 * by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
 */
protected static $trustedHeaders = array(
    self::HEADER_FORWARDED => 'FORWARDED',
    self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
    self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
    self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
    self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
);

/**
 * Returns the client IP addresses.
 *
 * In the returned array the most trusted IP address is first, and the
 * least trusted one last. The "real" client IP address is the last one,
 * but this is also the least trusted one. Trusted proxies are stripped.
 *
 * Use this method carefully; you should use getClientIp() instead.
 *
 * @return array The client IP addresses
 *
 * @see getClientIp()
 */
public function getClientIps()
{
    $clientIps = array();
    $ip = $this->server->get('REMOTE_ADDR');
    if (!$this->isFromTrustedProxy()) {
        return array($ip);
    }
    if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
        $forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
        preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
        $clientIps = $matches[3];
    } elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
        $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
    }
    $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
    $firstTrustedIp = null;
    foreach ($clientIps as $key => $clientIp) {
        // Remove port (unfortunately, it does happen)
        if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
            $clientIps[$key] = $clientIp = $match[1];
        }
        if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
            unset($clientIps[$key]);
        }
        if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
            unset($clientIps[$key]);
            // Fallback to this when the client IP falls into the range of trusted proxies
            if (null ===  $firstTrustedIp) {
                $firstTrustedIp = $clientIp;
            }
        }
    }
    // Now the IP chain contains only untrusted proxies and the client IP
    return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
}

अपरिभाषित संपत्ति: $ सर्वर
C47

0

मुझे आश्चर्य है कि किसी ने भी filter_input का उल्लेख नहीं किया है, इसलिए यहां Alix Axel का जवाब एक पंक्ति में दिया गया है:

function get_ip_address(&$keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'])
{
    return empty($keys) || ($ip = filter_input(INPUT_SERVER, array_pop($keys), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))? $ip : get_ip_address($keys);
}

-1

आप बहुत अपने सवाल का जवाब दिया! :)

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

स्रोत


-6
/**
 * Sanitizes IPv4 address according to Ilia Alshanetsky's book
 * "php|architect?s Guide to PHP Security", chapter 2, page 67.
 *
 * @param string $ip An IPv4 address
 */
public static function sanitizeIpAddress($ip = '')
{
if ($ip == '')
    {
    $rtnStr = '0.0.0.0';
    }
else
    {
    $rtnStr = long2ip(ip2long($ip));
    }

return $rtnStr;
}

//---------------------------------------------------

/**
 * Returns the sanitized HTTP_X_FORWARDED_FOR server variable.
 *
 */
public static function getXForwardedFor()
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
    $rtnStr = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
elseif (isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR']))
    {
    $rtnStr = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
    }
elseif (getenv('HTTP_X_FORWARDED_FOR'))
    {
    $rtnStr = getenv('HTTP_X_FORWARDED_FOR');
    }
else
    {
    $rtnStr = '';
    }

// Sanitize IPv4 address (Ilia Alshanetsky):
if ($rtnStr != '')
    {
    $rtnStr = explode(', ', $rtnStr);
    $rtnStr = self::sanitizeIpAddress($rtnStr[0]);
    }

return $rtnStr;
}

//---------------------------------------------------

/**
 * Returns the sanitized REMOTE_ADDR server variable.
 *
 */
public static function getRemoteAddr()
{
if (isset($_SERVER['REMOTE_ADDR']))
    {
    $rtnStr = $_SERVER['REMOTE_ADDR'];
    }
elseif (isset($HTTP_SERVER_VARS['REMOTE_ADDR']))
    {
    $rtnStr = $HTTP_SERVER_VARS['REMOTE_ADDR'];
    }
elseif (getenv('REMOTE_ADDR'))
    {
    $rtnStr = getenv('REMOTE_ADDR');
    }
else
    {
    $rtnStr = '';
    }

// Sanitize IPv4 address (Ilia Alshanetsky):
if ($rtnStr != '')
    {
    $rtnStr = explode(', ', $rtnStr);
    $rtnStr = self::sanitizeIpAddress($rtnStr[0]);
    }

return $rtnStr;
}

//---------------------------------------------------

/**
 * Returns the sanitized remote user and proxy IP addresses.
 *
 */
public static function getIpAndProxy()
{
$xForwarded = self::getXForwardedFor();
$remoteAddr = self::getRemoteAddr();

if ($xForwarded != '')
    {
    $ip    = $xForwarded;
    $proxy = $remoteAddr;
    }
else
    {
    $ip    = $remoteAddr;
    $proxy = '';
    }

return array($ip, $proxy);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.