说明:本文中的内容是我综合博客园上的博文和MSDN讨论区的资料,再通过自己的实际测试而得来,属于自己原创的内容说实话很少,写这一篇是为了记录自己在项目中做过的事情,同时也想抛砖引玉。参考的博文及其作者在下文均有提及。待到自己以后对HTTP、TCP/IP等知识学深入了,一定再来这里深入讨论这个内容。

一、名词

  首先说一下接下来要讲到的一些名词。

  在Web开发中,我们大多都习惯使用HTTP请求头中的某些属性来获取客户端的IP地址,常见的属性是REMOTE_ADDRHTTP_VIAHTTP_X_FORWARDED_FOR。

  这三个属性的含义,大概是如此:(摘自网上,欢迎指正)

  REMOTE_ADDR:该属性的值是客户端跟服务器“握手”时候的IP。如果使用了“匿名代理”,REMOTE_ADDR将显示代理服务器的IP。

  X-Forwarded-For:是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。

    XFF的有效性依赖于代理服务器提供的连接原始IP地址的真实性,因此, XFF的有效使用应该保证代理服务器是可信的, 比如可以通过建立可信服务器白名单的方式。

  这一HTTP头一般格式如下:

  X-Forwarded-For: client1, proxy1, proxy2

  其中的值通过逗号+空格,把多个IP地址区分开, 最左边(client1)是最原始客户端的IP地址, 代理服务器每成功收到一个请求,就把请求来源IP地址添加到右边。 在上面这个例子中,这个请求成功通过了三台代理服务器:proxy1, proxy2 及 proxy3。请求由client1发出,到达了proxy3(proxy3可能是请求的终点)。请求刚从client1中发出时,XFF是空的,请求被发往proxy1;通过proxy1的时候,client1被添加到XFF中,之后请求被发往proxy2;通过proxy2的时候,proxy1被添加到XFF中,之后请求被发往proxy3;通过proxy3时,proxy2被添加到XFF中,之后请求的的去向不明,如果proxy3不是请求终点,请求会被继续转发。

  鉴于伪造这一字段非常容易,应该谨慎使用X-Forwarded-For字段。正常情况下XFF中最后一个IP地址是最后一个代理服务器的IP地址, 这通常是一个比较可靠的信息来源。

  (另附维基中对X-Forwarded-For的完整介绍:http://zh.wikipedia.org/wiki/X-Forwarded-For

  至于在使用这些属性的时候,属性的值是什么,网上查到一份这样的博文:获取用户IP地址的三个属性的区别(原作者不详)。

  

  而在ASP.NET中,还可以通过另外一种方式获得客户端的IP地址,那就是通过Request对象中的UserHostAddress属性。在MSDN Library中,对这个属性是这样解释的:属性值是远程客户端的 IP 地址。

  如果客户端使用了代理服务器,那么Request.UserHostAddress属性获得的就是代理服务器的IP地址。

二、方法

  好了,讲了那么多概念性的东西,咱们来讲一下实现的方法。

  网上大多数方法的思路是:如果有代理IP,则优先获取代理IP,否则获取连接客户端的IP;或者调转过来,先获取连接客户端的IP,如获取失败,则获取代理IP。

  以下方法参考博文asp.net获取客户端IP (作者comeonfyz)

-----------------------------------------------------------------------------------------------------------

/// <summary>
/// 获取客户端IP地址
/// </summary>
/// <returns>若失败则返回回送地址</returns>
public static string GetIP()
{
//如果客户端使用了代理服务器,则利用HTTP_X_FORWARDED_FOR找到客户端IP地址
string userHostAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString().Split(',')[0].Trim();
//否则直接读取REMOTE_ADDR获取客户端IP地址
if (string.IsNullOrEmpty(userHostAddress))
{
userHostAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
//前两者均失败,则利用Request.UserHostAddress属性获取IP地址,但此时无法确定该IP是客户端IP还是代理IP
if (string.IsNullOrEmpty(userHostAddress))
{
userHostAddress = HttpContext.Current.Request.UserHostAddress;
}
//最后判断获取是否成功,并检查IP地址的格式(检查其格式非常重要)
if (!string.IsNullOrEmpty(userHostAddress) && IsIP(userHostAddress))
{
return userHostAddress;
}
return "127.0.0.1";
} /// <summary>
/// 检查IP地址格式
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static bool IsIP(string ip)
{
return System.Text.RegularExpressions.Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
}

-----------------------------------------------------------------------------------------------------------

  但是这样做有一个很严重的缺陷,那就是如大牛Kingthy在其博文 使用HTTP_X_FORWARDED_FOR获取客户端IP的严重后果   中所说的,"HTTP_X_FORWARDED_FOR"这个值是通过获取HTTP头的"X_FORWARDED_FOR"属性取得的,恶意破坏者可以很轻松地伪造IP地址;而且上文特别提到过,XFF的有效性依赖于代理服务器提供的连接原始IP地址的真实性,因此, XFF的有效使用应该保证代理服务器是可信的。但是作为开发者,我们既不知道用户的IP地址的真实性,更是难以分辨代理服务器的可信性。

  因此,综合各个方面的资料,我个人的想法与大牛Kingthy一样:无视代理

-----------------------------------------------------------------------------------------------------------

 1     /// <summary>
2 /// 获取客户端IP地址(无视代理)
3 /// </summary>
4 /// <returns>若失败则返回回送地址</returns>
5 public static string GetHostAddress()
6 {
7 string userHostAddress = HttpContext.Current.Request.UserHostAddress;
8
9 if (string.IsNullOrEmpty(userHostAddress))
10 {
11 userHostAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
12 }
13
14 //最后判断获取是否成功,并检查IP地址的格式(检查其格式非常重要)
15 if (!string.IsNullOrEmpty(userHostAddress) && IsIP(userHostAddress))
16 {
17 return userHostAddress;
18 }
19 return "127.0.0.1";
20 }
21
22 /// <summary>
23 /// 检查IP地址格式
24 /// </summary>
25 /// <param name="ip"></param>
26 /// <returns></returns>
27 public static bool IsIP(string ip)
28 {
29 return System.Text.RegularExpressions.Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
30 }

-----------------------------------------------------------------------------------------------------------

三、总结  

  无视代理服务器肯定不是最好的解决方案,如果项目需求明确说要客户端的真实地址,那肯定就不能无视代理服务器了。

  另外,我也向Artech大牛请教过这方面的问题,他虽然对这些没有深入的研究,但是他也认为没有一种IP获取方式是完全值得信赖的,因为这是TCP/IP协议本身决定的。

转自:http://www.cnblogs.com/stay-foolish/archive/2012/05/01/2475071.html

获取客户端IP地址 via C#的更多相关文章

  1. 在Thinkphp3.2.3框架下实现自动获取客户端IP地址的get_client_ip()函数

    在Thinkphp框架下使用get_client_ip()函数获取客户端IP地址十分方便: 一行代码便可以实现:$ip = get_client_ip(); 但当我们测试时会遇到后台获取的IP地址显示 ...

  2. JAVA获取客户端IP地址

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  3. (转)【ASP.NET开发】获取客户端IP地址 via C#

    [ASP.NET开发]获取客户端IP地址 via C# 说明:本文中的内容是我综合博客园上的博文和MSDN讨论区的资料,再通过自己的实际测试而得来,属于自己原创的内容说实话很少,写这一篇是为了记录自己 ...

  4. php获取客户端ip地址

    本文介绍一个,php获取客户端的IP地址的实例代码,有需要的朋友参考下吧. 获取客户端IP地址的代码,如下: 复制代码代码示例: <?php//取得客户端IP的函数function get_cl ...

  5. thinkphp 获取客户端ip地址方法

    /** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @param boolean $adv 是否进行高级模式获取(有 ...

  6. 获取客户端IP地址定位城市信息

    获取客户端IP地址定位城市信息 1.首先获取客户端的IP地址 function getIPaddress(){ $IPaddress=''; if (isset($_SERVER)){ if (iss ...

  7. Tp框架获取客户端IP地址

    /** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @return mixed */ function get_cl ...

  8. thinkphp之获取客户端IP地址

    /** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @return mixed */ function get_cl ...

  9. JAVA获取客户端IP地址和MAC地址

    1.获取客户端IP地址 public String getIp(HttpServletRequest request) throws Exception { String ip = request.g ...

随机推荐

  1. 2016.08.06计算几何总结测试day1

    T1 bzoj1132[POI2008]TRO 还是太弱了....测试时看到这题直接懵逼,极角排序什么的根本想不起来,只会n^3暴力怎么破......不过竟然有84.....QAQ 正解是n^2log ...

  2. 九度OJ 1118 数制转换

    题目地址:http://ac.jobdu.com/problem.php?pid=1118 题目描述: 求任意两个不同进制非负整数的转换(2进制-16进制),所给整数在long所能表达的范围之内.   ...

  3. 菜鸟的MySQL学习笔记(二)

    3-1约束: 1.约束保证数据的完整性和一致性: 2.约束分表级约束(两个或两个个以上字段的约束)和列级约束(一个字段约束): 3.NOT NULL       非空: PRIMARY KEY     ...

  4. leetcode problem (5) Longest Palindromic Substring

    最长回文子串: 1. 暴力搜索   时间复杂度O(n^3) 2. 动态规划 dp[i][j] 表示子串s[i…j]是否是回文 初始化:dp[i][i] = true (0 <= i <= ...

  5. uboot下 Nand flash 启动 内核与根文件系统

    u-boot版本: u-boot-2010.03_tekkamanninja修改的u-boot 1.将uboot通过j-link烧写到norflash,启动后 saveenv 将参数保存到 nandf ...

  6. Linux网络应用编程之集线器(Packet Tracer仿真)

    Packet Tracer入门 一,集线器概况 对接收到的信号进行再生整形放大,以扩大网络的传输距离,同时把所有节点集中在以它为中心的节点上. 工作于OSI(开放式系统互联参考模型)的最底层(物理层) ...

  7. 简单的doc命令

    cd 切换目录 dir 显示目录列表 mkdir 创建目录(mkdir) rmdir 删除空目录(rmdir test) rmdir  /s 删除非空目录(rmdir test /s) echo 创建 ...

  8. left join, right join , inner join, join, union的意义

    数据库在连接两张或以上的表来返回数据时,都会生成一张中间的临时表,然后再将临时表返回给用户left join,right join,inner join, join 与 on 配合用 select c ...

  9. 基于jquery实现的文字淡入淡出效果

    这篇文章介绍了jquery实现的文字淡入淡出效果实例,有需要的朋友可以参考一下 复制代码代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...

  10. zzuli oj 1167逆转数(指针专题)

    Description 任意给你一个整数,这个数可能很大(最长不超过100位),你能求出它的逆转数吗?  逆转数定义如下:  1.一个末尾没有0的整数,它的逆转数就是各位数字逆序输出:  2.一个负数 ...