PHP самый точный/безопасный способ получить реальный IP-адрес пользователя в 2017 году

Каков самый точный способ получить IP-адрес пользователя в 2017 году через PHP?

Я прочитал много SO вопросов и ответов об этом, но большинство ответов устарело и прокомментировано пользователями, что эти способы небезопасны.

Например, взгляните на этот вопрос (2011): Как получить IP-адрес клиента на PHP?

В ответе Тима Кеннеди содержится рекомендация использовать что-то вроде:

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

Но, как я много читал, я видел, что использовать X_FORWARDED_FOR небезопасно, так как в комментарии ниже подчеркивается:

НЕ используйте приведенный выше код, если не знаете ТОЧНО, что он делает! Я из-за этого были обнаружены дыры в безопасности MASSIVE. Клиент может установить X-Forwarded-For или заголовок Client-IP для любого произвольного значения хочет. Если у вас нет доверенного обратного прокси, вы не должны использовать этих значений.

Как я не знал ТОЧНО, что он делает, я не хочу рисковать. Он сказал, что это небезопасно, но не предоставил безопасный метод для получения IP-адреса пользователя.

Я пробовал простой $_SERVER['REMOTE_ADDR'];, но это возвращает неправильный IP. Я тестировал это, и мой реальный IP следует этому шаблону: 78.57.xxx.xxx, но я получаю IP-адрес, например: 81.7.xxx.xxx

У вас есть идеи?

Ответ 1

Короткий ответ:

$ip = $_SERVER['REMOTE_ADDR'];


По состоянию на 2019 год $_SERVER['REMOTE_ADDR']; Это единственный надежный способ получить IP-адрес пользователя, но он может показывать ошибочные результаты, если находится за прокси-сервером.
Все другие решения предполагают риски безопасности или могут быть легко подделаны.

Ответ 2

Из безопасности POV ничего, кроме $_SERVER['REMOTE_ADDR'], не является надежным - это просто простая правда, к сожалению.

Все переменные с префиксом HTTP_ на самом деле являются HTTP-заголовками, отправленными клиентом, и там нет другого способа передачи этой информации, пока запросы проходят через разные серверы.
Но это, конечно, автоматически означает, что клиенты могут обманывать эти заголовки.

Вы никогда не сможете доверять клиенту.

Если это не вы... Если вы управляете прокси-сервером или балансировщиком нагрузки, его можно настроить таким образом, чтобы он удалял такие заголовки из исходного запроса.
Затем, и только тогда вы можете доверять, например, X-Client-IP, но на самом деле в этом нет необходимости... ваш веб-сервер также может быть настроен на замену REMOTE_ADDR на это значение, и весь процесс станет прозрачным для вас.

Это всегда будет иметь место, независимо от того, в каком году мы находимся... для чего-то связанного с безопасностью - только доверие REMOTE_ADDR.
Лучший сценарий - считывать данные HTTP_ для статистических целей только, и даже тогда - убедитесь, что вход является хотя бы допустимым IP-адресом.

Ответ 3

Вы должны сотрудничать со своей командой sysops (или если вы тоже носите эту шляпу, вам нужно будет провести некоторое исследование). Проверка заголовка используется, когда ваша сетевая инфраструктура настроена определенным образом, когда удаленный реквестер является одним из ваших сетевых устройств, а не концом пользователь.

Такое происходит, когда ваш веб-сервер сидит за балансировщиком нагрузки или брандмауэром или другим устройством, которое должно запросить полезную нагрузку для правильной обработки. Например, когда балансировщик нагрузки завершил ssl и отправил запрос на веб-сервер без ssl. Когда это происходит, удаленный адрес становится балансировщиком нагрузки. Это также случается с устройствами брандмауэра, которые делают то же самое.

В большинстве случаев устройство предложит конфигурацию для установки значения заголовка в запросе с исходным удаленным IP-адресом. Заголовок обычно является тем, что вы ожидаете, но в некоторых случаях он может быть другим или даже настраиваться.

Что еще, в зависимости от конфигурации вашего веб-сервера (apache, nginx или другого), может не поддерживаться или быть в настоящее время настроено для поддержки определенных пользовательских заголовков, таких как общий заголовок ip.

Точка в том, что вам нужно будет исследовать конфигурацию вашей сети, чтобы убедиться, что исходный запросчик ip полностью перешел на ваш код приложения и в какой форме.

Ответ 4

Если вы хотите использовать готовую библиотеку, вы можете использовать Whip.

Использование готовых библиотек обычно лучше, поскольку большинство из них будет тщательно проверено активным сообществом. Некоторые из них, особенно те, которые были вокруг в течение долгого времени, имеют больше встроенных функций.

Но если вы хотите написать код самостоятельно, чтобы изучить концепцию, тогда, я думаю, все в порядке. Я рекомендую упаковать его как отдельную библиотеку и выпустить как открытый исходный код :)

РЕДАКТИРОВАТЬ: я не рекомендую использовать удаленный IP в механизмах безопасности, поскольку они не всегда надежны.

Ответ 5

Во-первых, невозможно надежно определить IP-адрес источника-источника, если они намерены скрываться. Даже то, что сегодня кажется безупречным, скоро будет иметь лазейку (если этого еще нет). Таким образом, любой ответ ниже следует рассматривать как UNTRUSTED, что означает, что если вы положите все яйца в эту корзину, будьте готовы к тому, чтобы кто-то воспользовался им или обошел его как-то.

Я не буду входить во все способы, по которым кто-то может обойти IP-отслеживание, потому что он постоянно развивается. Я бы сказал, что это может быть полезным инструментом для ведения журнала, если вы знаете, что IP-адреса могут легко меняться или в противном случае маскироваться.

Теперь, одна большая точка зрения заключается в том, что существует разница между общедоступным IP-адресом и частным IP-адресом. В IPV4 маршрутизаторам обычно присваивается один общедоступный IP-адрес, который все, что серверный язык может фактически захватить, поскольку он не видит ваш IP-адрес на стороне клиента. Для сервера ваш компьютер не существует как веб-пространство. Вместо этого ваш маршрутизатор - это все, что имеет значение. В свою очередь, ваш маршрутизатор - это единственное, что волнует ваш компьютер, и он назначает частный IP-адрес (к которому ваши 172... * адрес принадлежит), чтобы сделать эту работу. Это хорошо для вас, потому что вы не можете напрямую обращаться к компьютеру за маршрутизатором.

Если вы хотите получить доступ к частному IP-адресу, вам необходимо использовать JavaScript (язык на стороне клиента). Затем вы можете сохранить данные асинхронно через AJAX. Насколько мне известно, в настоящее время это возможно только с помощью Chrome и Firefox с поддержкой WebRTC. См. здесь для демонстрации.

Я тестировал это, и он возвращает частные IP-адреса. Обычно я думаю, что это используется рекламодателями для отслеживания отдельных пользователей в сети в сочетании с общедоступным IP-адресом. Я уверен, что он быстро станет бесполезным, так как люди придумают обходные пути или как общественный резонанс заставляет их предлагать возможность отключить API WebRTC. Однако пока это работает для всех, у кого есть JavaScript в Chrome и Firefox.

Подробнее Чтение:

Ответ 6

Поскольку реальный метод проверки IP-адреса пользователя - $ip = $_SERVER['REMOTE_ADDR'];

Если пользователь использует VPN или какой-либо прокси-сервер, он не будет определять исходный IP-адрес.

Ответ 7

Получить IP-адрес клиента:

<?php
 echo   $ip = $_SERVER['REMOTE_ADDR'];
?>

Примечание::      Это будет работать только на реальном сайте, потому что на вашем локальном хосте ваш ip будет одним (1) внутренних IP-адресов, например 127.0.0.1      Итак, его Return:: 1

Пример: https://www.virendrachandak.com/demos/getting-real-client-ip-address-in-php.php

Показать свой локальный Ip:  Как... 78.57.xxx.xxx

Пример:

<?php
$myIp= getHostByName(php_uname('n'));
 echo $myIp;
?>

Ответ 8

Как насчет этого -

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

Ответ 9

Я использую этот код, и он работает для меня. Посмотрите на него.

<?php

// Gets client 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;

?>

Здесь, рабочий пример. Надеюсь, это поможет!

Ответ 10

Код, похожий на ваш, - единственный способ получить IP-адрес клиента. Вам просто нужно применить filter_var к нему (beacause, если он может быть помечен, как указано вашей цитатой).

Это может быть хорошим источником для создания правильного и защищенного кода.