使用PHP获取客户端真实IP地址?——不可能!
网上一直流传着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