比较 HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR
REMOTE_ADDR
最近做项目的时候,遇到一个需要记录客户端ip的,后台语言是php,我想了一下,用REMOTE_ADDR
吧。可是呢,后来发现其实这个还有很多其他的获取方式,HTTP_CLIENT_IP
, HTTP_X_FORWARDED_FOR
都可以获取,我仔细查了一下资料,总结一下这三者的区别,另附完整解决方法:
-
HTTP_CLIENT_IP
头是有的,只是未成标准,不一定服务器都实现了。 -
HTTP_X_FORWARDED_FOR
是有标准定义,用来识别经过HTTP代理
后的客户端IP地址,格式:clientip,proxy1,proxy2
。详细解释见 http://zh.wikipedia.org/wiki/X-Forwarded-For -
REMOTE_ADDR
是可靠的, 它是最后一个跟你的服务器握手的IP
,可能是用户的代理服务器,也可能是自己的反向代理。
顺便说下$_SERVER和getenv的区别,getenv不支持IIS的isapi方式运行的php
function getIp() {
if (getenv ( "HTTP_CLIENT_IP" ) && strcasecmp ( getenv ( "HTTP_CLIENT_IP" ), "unknown" )) {
$ip = getenv ( "HTTP_CLIENT_IP" );
} elseif (getenv ( "HTTP_X_FORWARDED_FOR" ) && strcasecmp ( getenv ( "HTTP_X_FORWARDED_FOR" ), "unknown" )) {
$ip = getenv ( "HTTP_X_FORWARDED_FOR" );
} elseif (getenv ( "REMOTE_ADDR" ) && strcasecmp ( getenv ( "REMOTE_ADDR" ), "unknown" )) {
$ip = getenv ( "REMOTE_ADDR" );
} elseif (isset ( $_SERVER ['REMOTE_ADDR'] ) && $_SERVER ['REMOTE_ADDR'] && strcasecmp ( $_SERVER ['REMOTE_ADDR'], "unknown" )) {
$ip = $_SERVER ['REMOTE_ADDR'];
} else {
$ip = "unknown";
}
return ($ip);
}
REMOTE_ADDR
不可以显式的伪造,虽然可以通过代理将ip地址隐藏,但是这个地址仍然具有参考价值,因为它就是与你的服务器实际连接的ip地址。
相比之下,前两种ip地址都可以通过http header来伪造,但并不意味着它们一无是处。生产环境中很多服务器隐藏在负载均衡节点后面,你通过REMOTE_ADDR
只能获取到负载均衡节点的ip地址,一般的负载均衡节点会把前端实际的ip地址通过HTTP_CLIENT_IP
或者HTTP_X_FORWARDED_FOR
这两种http头传递过来