【问题标题】:Problem getting real IP in php在php中获取真实IP的问题
【发布时间】:2010-06-17 15:41:21
【问题描述】:

我正在使用它来获取真实IP,但我从$_SERVER['HTTP_CLIENT_IP'] 取空,我只从$_SERVER['REMOTE_ADDR'] 取空。但我不需要代理的IP,我需要使用某些内部网的计算机的真实IP。我能得到它吗? $_SERVER['HTTP_CLIENT_IP']什么时候不返回空?

function getRealIpAddr()
{
    if (!empty($_SERVER['HTTP_CLIENT_IP']))   //check ip from share internet
    {
      $ip=$_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //to check ip is pass from proxy
    {
      $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else
    {
      $ip=$_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

【问题讨论】:

  • 没有办法 100% 获得“真实 IP”。
  • 如果您将 IP 用于任何重要的事情,请小心。欺骗(伪造)IP 来欺骗您的应用程序是微不足道的。

标签: php


【解决方案1】:

此页面上的功能不可靠。

来自$ip = $_SERVER["REMOTE_ADDR"];的唯一可靠IP 否则任何人都可以通过发送 CLIENT_IP 标头来伪造他的 IP 地址。

This Firefox Addon 可以帮助您发送自定义标头。将 CLIENT_IP=x.x.x.x 标头发送到运行此页面上的任何功能的服务器,意味着客户端可以选择他们想要的任何 IP...

【讨论】:

  • 更明确地说,您无法知道您获得的 REMOTE_ADDR 是最终客户端的还是中间代理的,并且您无法知道 X-Forwarded-For 是由代理添加还是被用户。如果您在 PHP 前运行自己的反向代理,那么假设 X-Forwarded-For 中的 last 值是由您自己的代理添加的可能会更安全。但是,无论您是否在反向代理后面,您都无法编写可以正常工作的通用代码。
【解决方案2】:

HTTP_CLIENT_IP 未在$_SERVER documentation 中指定...它可能以environmental variable 的形式提供(在$_ENV 下),但不在$_SERVER 中。你正在使用的方法(去HTTP_X_FORWARDED_FOR,然后回到REMOTE_ADDR)是你能做的最好的......

【讨论】:

  • 这是一个相当关键的问题。现在只是测试一下,事实上,HTTP_CLIENT_IP 不在我们的 apache $_SERVER 值中,正如您所指出的,正确。
【解决方案3】:

您正在做的是关于您可以做的所有事情来获取此信息。我不能 100% 确定您在说什么,但请尝试以下 2 种方法,看看它们是否会为您提供不同/更好的信息。

试试:

$headers = apache_request_headers(); 
echo $headers['X-Forwarded-For'];

或者:

$ip_list = getenv('HTTP_X_FORWARDED_FOR');
echo $ip_list;

【讨论】:

  • 只有 getenv('REMOTE_ADDR') 返回代理的 ip 所有其他:getenv('HTTP_X_FORWARDED_FOR'); getenv('HTTP_CLIENT_IP');返回空???
  • @leda: 和另一个建议:$headers = apache_request_headers(); echo $headers['X-Forwarded-For']; 那会返回什么?
【解决方案4】:

不可能 100% 地解决这个问题,但这会让你尽可能接近:

if($_SERVER["HTTP_X_FORWARDED_FOR"]) {
    if($_SERVER["HTTP_CLIENT_IP"]) {
        $proxy = $_SERVER["HTTP_CLIENT_IP"];
    } else {
        $proxy = $_SERVER["REMOTE_ADDR"];
    }

    $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} else {
    if($_SERVER["HTTP_CLIENT_IP"]) {
        $ip = $_SERVER["HTTP_CLIENT_IP"];
    } else {
        $ip = $_SERVER["REMOTE_ADDR"];
    }
}

echo "IP resolved to: ".$ip." (could still be a proxy IP though)<br>";
if($proxy) echo "Proxied through: ".$proxy;

【讨论】:

  • HTTP_X_FORWARDED_FOR 以逗号分隔。因此,您的代码中存在错误。
【解决方案5】:

我认为这是获取真实ip的最好方法之一

作者:奥利弗 leuyim 天使

function getRealIP(){
    if( $_SERVER['HTTP_X_FORWARDED_FOR'] != '' ) { 
        $client_ip = ( !empty($_SERVER['REMOTE_ADDR']) ) ? $_SERVER['REMOTE_ADDR'] :(( !empty($_ENV['REMOTE_ADDR']) ) ? $_ENV['REMOTE_ADDR'] : "unknown" );

        // los proxys van añadiendo al final de esta cabecera
        // las direcciones ip que van "ocultando". Para localizar la ip real
        // del usuario se comienza a mirar por el principio hasta encontrar
        // una dirección ip que no sea del rango privado. En caso de no
        // encontrarse ninguna se toma como valor el REMOTE_ADDR

        $entries = split('[, ]', $_SERVER['HTTP_X_FORWARDED_FOR']);
        reset($entries);
        while (list(, $entry) = each($entries)){
            $entry = trim($entry);
            if ( preg_match("/^([0-9]+.[0-9]+.[0-9]+.[0-9]+)/", $entry, $ip_list) ){
                // http://www.faqs.org/rfcs/rfc1918.html
                $private_ip = array(
                    '/^0./',
                    '/^127.0.0.1/',
                    '/^192.168..*/',
                    '/^172.((1[6-9])|(2[0-9])|(3[0-1]))..*/',
                    '/^10..*/');
                $found_ip = preg_replace($private_ip, $client_ip, $ip_list[1]);
                if ($client_ip != $found_ip){
                    $client_ip = $found_ip;
                    break;
                }
            }
        }
    } else {
        $client_ip = ( !empty($_SERVER['REMOTE_ADDR']) ) ? $_SERVER['REMOTE_ADDR'] : ( ( !empty($_ENV['REMOTE_ADDR']) ) ? $_ENV['REMOTE_ADDR'] : "unknown" );
        if ($client_ip == 'unknown') {
            if (!empty($_SERVER['HTTP_CLIENT_IP']))   //check ip from share internet
            {
                $ip=$_SERVER['HTTP_CLIENT_IP'];}
                elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //to check ip is pass from proxy
                {
                    $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
                }
                else { 
                    $ip=$_SERVER['REMOTE_ADDR'];
                }
                $client_ip = $ip;
            }
        }
    return $client_ip;
}

【讨论】:

  • 这个函数有点乱,包含一些无效的逻辑——如果HTTP_X_FORWARDED_FOR为空,为什么稍后再检查?
  • 另外,HTTP_X_FORWARDED_FOR 返回移动网络的 IPv6 地址(至少我在测试真实用户的值时看到的每个当前的美国电话用户),这进一步使这种技术无效,所以你想假设所有访问的手机都将显示 ipv6 地址。这意味着您的内部系统也必须进行编码以支持这些。
【解决方案6】:

匿名代理不会填充 HTTP_X_FORWARDED_FOR 或 REMOTE_ADDR,或者会使用自己的 IP 地址而不是客户端 IP 地址填充它们。

如果您正在做的事情绝对必须识别客户端计算机正在使用的网关的 IP 地址,并且必须处理使用匿名代理的情况,那么您将不得不想出其他办法。我过去曾使用 flash 与服务器建立套接字连接,并通过 params 向 flash 发送一个唯一密钥。

请注意,这不是一个完美的解决方案。但在我使用它的情况下,为了防止在投票应用程序上作弊,它运行良好。没有闪光,没有投票。类似的事情可以用 Java 小程序、silverlight 等来完成。任何可以指定与服务器通信的端口的客户端技术。您不想使用 80、8080 等任何常见的代理端口。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-10
    • 2011-07-22
    • 2013-12-24
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多