目前网上流行的所谓“取真实ip地址”的方法,都有bug,没有考虑到多层透明代理的情况。多数代码类似:
stringIpAddress=(HttpContext.Current.Request.
ServerVariables["HTTP_X_FORWARDED_FOR"]!=null
&&HttpContext.Current.Request.ServerVariables
["HTTP_X_FORWARDED_FOR"]!=String.Empty)
?HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]
:HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
事实上,上面的代码只试用与用户只使用了1层代理,如果用户有2层,3层http_x_forwarded_for的值是:“本机真实IP,1层代理IP,2层代理IP,……”,如果这个时候你的数据中保存IP字段的长度很小(15个字节),数据库就报错了。
实际应用中,因为使用多层透明代理的情况比较少,所以这种用户并不多。其他应用情况,现在越来越多的网站使用了代理加速方式,比如新浪、SOHU的新闻都使用Squid做代理方式,利用多台服务器分流。Squid本身类似透明代理,会发送“HTTP_X_FORWARDED_FOR”,HTTP_X_FORWARDED_FOR中包括客户的IP地址,如果此时客户已经使用了一层透明代理,那么程序取的“HTTP_X_FORWARDED_FOR”就包括两个IP地址。(我遇到过3个IP地址的情况,4个的未遇到过)
所以取“真正”IP地址的方式,还应该判断“HTTP_X_FORWARDED_FOR”中是否有“,”逗号,或者长度是否超长(超过15字节xxx.xxx.xxx.xxx)。
代码如下:
/**////
///取得客户端真实IP。如果有代理则取第一个非内网地址
///
publicstaticstringIPAddress
{
get
{
stringresult=String.Empty;
result=HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if(result!=null&&result!=String.Empty)
{
//可能有代理
if(result.IndexOf(".")==-1)//没有“.”肯定是非IPv4格式
result=null;
else
{
if(result.IndexOf(",")!=-1)
{
//有“,”,估计多个代理。取第一个不是内网的IP。
result=result.Replace("","").Replace("'","");
string[]temparyip=result.Split(",;".ToCharArray());
for(inti=0;i {
if(Text.IsIPAddress(temparyip[i])
&&temparyip[i].Substring(0,3)!="10."
&&temparyip[i].Substring(0,7)!="192.168"
&&temparyip[i].Substring(0,7)!="172.16.")
{
returntemparyip[i];//找到不是内网的地址
}
}
}
elseif(Text.IsIPAddress(result))//代理即是IP格式
returnresult;
else
result=null;//代理中的内容非IP,取IP
}
}
stringIpAddress=(HttpContext.Current.Request.
ServerVariables["HTTP_X_FORWARDED_FOR"]!=null&&HttpContext.
Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]!=
String.Empty)?HttpContext.Current.Request.ServerVariables
["HTTP_X_FORWARDED_FOR"]:HttpContext.Current.Request.
ServerVariables["REMOTE_ADDR"];
if(null==result||result==String.Empty)
result=HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
if(result==null||result==String.Empty)
result=HttpContext.Current.Request.UserHostAddress;
returnresult;
}
}
取“HTTP_X_FORWARDED_FOR”的弊端:
HTTP_X_FORWARDED_FOR是HTTP协议中头的一部分,不影响TCP的通讯。也就是说实际上客户端可以发送任意内容的HTTP_X_FORWARDED_FOR,以就是伪造IP。最简单的是WEB程序的IP记录,本来是要记录真实IP的,反而被“黑客”欺骗。当你的应用程序记录客户的访问IP、拒绝或允许部分IP的访问、错误日志都会出错,甚至误杀。
因此必要的安全日志应该记录完整的“HTTP_X_FORWARDED_FOR”(至少给数据库中的字段分配3*15+2个字节,以记录至少3个IP)和“REMOTE_ADDR”。对HTTP_X_FORWARDED_FOR的IP格式检查也是不可少的。
获得客户端真实的IP地址:
Private Function getIP()
Dim strIPAddr
If Request.ServerVariables("HTTP_X_FORWARDED_FOR") = "" OR InStr(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), "unknown") > 0 Then
strIPAddr = Request.ServerVariables("REMOTE_ADDR")
ElseIf InStr(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), ",") > 0 Then
strIPAddr = Mid(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), 1, InStr(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), ",")-1)
ElseIf InStr(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), ";") > 0 Then
strIPAddr = Mid(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), 1, InStr(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), ";")-1)
Else
strIPAddr = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
End If
getIP = Trim(Mid(strIPAddr, 1, 30))
End Function (DVOL本文转自:中国DV传媒 http://www.dvol.cn)