使用PHP获取客户端真实IP地址?——不可能!

2017-06-26T19:42:00

网上一直流传着PHP获取客户端的真实IP地址,无论是怎样的流程无非是通过检查以下参数是否存在来获取IP地址:

HTTP_CLIENT_IP
HTTP_X_REAL_FORWARDED_FOR
HTTP_X_FORWARDED_FOR
REMOTE_ADDR

大部分都是依次检查$_SERVER['']中是否存在上上述参数且不为空则break,那个该值就是IP地址。但需要注意的是:HTTP_CLIENT_IP 和 HTTP_X_FORWARDED_FOR 都是可以通过http头部伪造的。

比如:

$http_header[] = 'X-FORWARDED-FOR: 8.8.8.8';
$http_header[] = 'HTTP_X_REAL_FORWARDED_FOR: 8.8.8.8';
$http_header[] = 'CLIENT-IP: 8.8.8.8';

只有REMOTE_ADDR 始终反映出接入网络的第一级路由的 ip,这才是真实的 ip。

事实上,当客户端使用代理的时候,REMOTE_ADDR就会变得不堪一击,而前三个参数却能够获取客户端的真实IP地址。

可是,我们作为良好公司和良好市民,开代理的人毕竟是少数,躲不掉也没辙。一般情况下可以通过以下方法获取客户端的真实IP,但是对代理IP无效。

/**
 *@功能:获取客户端的真实IP地址,对代理IP无效
 *@参数:null
 *@返回:客户端的IP地址
 */
function get_client_ip()
{
    $ip = 'unknown';
    $pattern = '/((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))/';
    if(isset($_SERVER['REMOTE_ADDR']) && preg_match($pattern, $_SERVER['REMOTE_ADDR']))
    {
        $ip = $_SERVER['REMOTE_ADDR'];
    }else if(isset($_SERVER['HTTP_X_REAL_FORWARDED_FOR']) && preg_match($pattern, $_SERVER['HTTP_X_REAL_FORWARDED_FOR']))
    {
        $ip = $_SERVER['HTTP_X_REAL_FORWARDED_FOR'];
    }elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match($pattern, $_SERVER['HTTP_X_FORWARDED_FOR'])){
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }elseif(isset($_SERVER['HTTP_CLIENT_IP']) && preg_match($pattern, $_SERVER['HTTP_CLIENT_IP'])){
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    }
    return $ip;
}

同样,考虑到使用cdn加速的网站获取真实IP或代理IP的例子:

/**
 *@功能:获取客户端的代理IP地址,很容易被程序篡改
 *@参数:null
 *@返回:客户端的IP地址
 */
function get_proxy_ip()
{
    $arr_ip_header = array(
        'HTTP_CDN_SRC_IP',
        'HTTP_PROXY_CLIENT_IP',
        'HTTP_WL_PROXY_CLIENT_IP',
        'HTTP_CLIENT_IP',
        'HTTP_X_FORWARDED_FOR',
        'REMOTE_ADDR',
    );
    $client_ip = 'unknown';
    foreach ($arr_ip_header as $key)
    {
        if (!empty($_SERVER[$key]) && strtolower($_SERVER[$key]) != 'unknown')
        {
            $client_ip = $_SERVER[$key];
            break;
        }
    }
    return $client_ip;
}

对于PHP获取客户端真实IP,我目前还没找到解决办法,除非我能认定这个客户端有没有使用高匿名代理!

 

普及一下代理小知识:

什么是高匿名、匿名和透明代理?它们有什么区别?

HTTP代理按匿名度可分为透明代理、匿名代理和高度匿名代理。

使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP。

透明代理访问对方服务器所带的HTTP头信息如下:
REMOTE_ADDR = 代理服务器IP
HTTP_VIA = 代理服务器IP
HTTP_X_FORWARDED_FOR = 你的真实IP
透明代理还是将你的真实IP发送给了对方服务器,因此无法达到隐藏身份的目的。

使用匿名代理,对方服务器可以知道你使用了代理,但不知道你的真实IP。

匿名代理访问对方服务器所带的HTTP头信息如下:
REMOTE_ADDR = 代理服务器IP
HTTP_VIA = 代理服务器IP
HTTP_X_FORWARDED_FOR = 代理服务器IP
匿名代理隐藏了你的真实IP,但是向访问对象透露了你是使用代理服务器访问他们的。

使用高匿名代理,对方服务器不知道你使用了代理,更不知道你的真实IP。

高匿名代理访问对方服务器所带的HTTP头信息如下:
REMOTE_ADDR = 代理服务器IP
HTTP_VIA 不显示
HTTP_X_FORWARDED_FOR 不显示
高匿名代理隐藏了你的真实IP,同时访问对象也不知道你使用了代理,因此隐蔽度最高。

 

然而,在nginx中有一个模块可以屏蔽某个IP的访问:http_realip_module,需要在编译的时候加上

--with-http_realip_module

然后再nginx.conf的http段内添加

include blockips.conf;

新建blockips.conf文件放在nginx.conf同级目录下,内容如下:

#deny 8.8.8.8;
# block all ips
# deny all;
# allow all ips
# allow all;

显然,通过这种简单方式即可屏蔽8.8.8.8。如果想屏蔽一整个IP段,也可以这样写:

deny 91.212.45.0/24;
deny 91.212.65.0/24;

如何禁止所有外网ip,仅允许内网ip呢?

location / {
  # block one workstation
  deny    192.168.1.1;
  # allow anyone in 192.168.1.0/24
  allow   192.168.1.0/24;
  # drop rest of the world
  deny    all;
}

如何格式化nginx的403页面呢?

首先执行下面的命令:

cd /usr/local/nginx/html
vi error403.html

然后输入403的文件内容,例如:

<html>
<head><title>Error 403 - IP Address Blocked</title></head>
<body>
Your IP Address is blocked. If you this an error, please contact webmaster with your IP at [email protected]
</body>
</html>

如果启用了SSI,可以在403中显示被封的客户端ip,如下:

Your IP Address is <!--#echo var="REMOTE_ADDR" --> blocked.

保存error403文件,然后打开nginx的配置文件vi nginx.conf,在server配置节内添加下面内容

# redirect server error pages to the static page
error_page   403  /error403.html;
location = /error403.html {
 root   html;
}

然后保存配置文件,通过nginx -t命令测试配置文件是否正确,若正确通过nginx -s reload载入配置。

 

使用nginx来屏蔽客户端的非法IP很有效。PS.目前本人的爬虫被www.XXXXXX.com屏蔽,没使用代理情况下无法正常工作。

 

via。http://blog.zhengshuiguang.com/php/php-ip.html

当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »
因本文不是用Markdown格式的编辑器书写的,转换的页面可能不符合MIP标准。