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

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

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

$ip = $_SERVER['REMOTE_ADDR'];


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Во-первых, невозможно надежно определить чей-то исходный IP-адрес, если они намерены быть скрытыми. Даже то, что сегодня кажется безупречным, скоро будет иметь лазейку (если этого еще нет). Таким образом, любой ответ ниже следует считать НЕОБХОДИМЫМ , что означает, что если вы положите все яйца в эту корзину, будьте готовы к тому, чтобы кто-то воспользовался им или обойдя его каким-то образом.

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

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

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

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

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

  • Что такое частная сеть?
  • Запросы STUN IP-адресов для WebRTC
  • Быстрая ссылка: проверка IP-адреса

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

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

Получить 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

Его Show Your Local Ip: Как … 78.57.xxx.xxx

Пример:

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

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

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

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

 <?php // Gets client's 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; ?> 

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

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

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