说明:本文中的内容是我综合博客园上的博文和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协议本身决定的。

  附上Artech大牛给我的一份资料,分享分享。http://www.symantec.com/connect/articles/ip-spoofing-introduction

 

转载来源:https://www.cnblogs.com/stay-foolish/archive/2012/05/01/2475071.html

C# 获取用户IP地址(转载)的更多相关文章

  1. easyui datagrid 禁止选中行 EF的增删改查(转载) C# 获取用户IP地址(转载) MVC EF 执行SQL语句(转载) 在EF中执行SQL语句(转载) EF中使用SQL语句或存储过程 .net MVC使用Session验证用户登录 PowerDesigner 参照完整性约束(转载)

    easyui datagrid 禁止选中行   没有找到可以直接禁止的属性,但是找到两个间接禁止的方式. 方式一: //onClickRow: function (rowIndex, rowData) ...

  2. Flask框架获取用户IP地址的方法

    本文实例讲述了python使用Flask框架获取用户IP地址的方法.分享给大家供大家参考.具体如下: 下面的代码包含了html页面和python代码,非常详细,如果你正使用Flask,也可以学习一下最 ...

  3. 获取用户Ip地址通用方法常见安全隐患(HTTP_X_FORWARDED_FOR)

    分析过程 这个来自一些项目中,获取用户Ip,进行用户操作行为的记录,是常见并且经常使用的. 一般朋友,都会看到如下通用获取IP地址方法. function getIP() { if (isset($_ ...

  4. 【用jQuery来判断浏览器的类型】及【javascript获取用户ip地址】

    用jQuery来判断浏览器的类型,主要是使用$.browser这个工具类,使用方法: $.browser.['浏览器关键字'] //谷歌浏览器.360浏览器等其他一些浏览器,没有专门的判断 funct ...

  5. PHP获取用户IP地址

    PHP获取访问者IP地址 这是一段 PHP 代码,演示了如何获得来访者的IP address. <?php//打印出IP地址:echo (GetIP());function GetIP()  / ...

  6. 用户登录时,获取用户ip地址

    使用django来获取用户访问的IP地址,如果用户是正常情况下通过request.META['REMOTE_ADDR']  可以获得用户的IP地址.但是有些网站服务器会使用ngix等代理http,或者 ...

  7. 采用CDN加速后,如何在程序里获取用户IP地址

    现在很多网站用了CDN技术,但采用CDN技术后,原来用来获取访问源的IP地址的程序已不能正常使用,它拿到的并不是访问源的真实IP地址,而是CDN节点的IP地址,解决方法是对获取IP的代码作一点小改动. ...

  8. 获取用户IP地址

    // <summary> /// 取得客户端真实IP.如果有代理则取第一个非内网地址 /// by flower.b /// </summary> public static ...

  9. 获取用户Ip地址通用方法

    1 public static function getIp() 2 { 3 if ($HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"]) 4 { ...

随机推荐

  1. Event对象和触发

    1.构造: //非IE浏览器事件构造方法 var event = document.createEvent('HTMLEvents');//'HTMLEvents'自定义事件名 //IE浏览器构造方法 ...

  2. visual2017专业版MFC编程环境搭建及第一个MFC程序的创建

    1.MFC介绍及环境搭建 MFC全程为Microsoft Foundation class Library,即微软的基本类库,MFC实际上是一个庞大的文件库,它由指向文件和源文件组成. 首先,打开vi ...

  3. 使用Python对Twitter进行数据挖掘(Mining Twitter Data with Python)

    目录 1.Collecting data 1.1 Register Your App 1.2 Accessing the Data 1.3 Streaming 2.Text Pre-processin ...

  4. k8s docker集群搭建

    一.Kubernetes系列之介绍篇   •Kubernetes介绍 1.背景介绍 云计算飞速发展 - IaaS - PaaS - SaaS Docker技术突飞猛进 - 一次构建,到处运行 - 容器 ...

  5. 【牛客网71E】 组一组(差分约束,拆位)

    传送门 NowCoder Solution 考虑一下看到这种区间或与区间与的关系,拆一下位. 令\(s_i\)表示前缀和,则: 那么如果现在考虑到了第\(i\)为,有如下4种可能: \(opt=1\) ...

  6. 【BZOJ4025】 二分图(线段树分治)

    传送门 BZOJ Solution 只是为了学习一下线段树分治的啦! 当你学会线段树分治之后,可以跳过下面的一部分: 按照时间搞一颗线段树出来,把包含这段区间的操作用vector压进去. 每一个线段树 ...

  7. 解决Eclipse中DDMS一直打印输出Connection attempts的问题

    Eclipse/MyEclipse出现以下错误的解决方案: [2015-01-25 16:10:29 - DeviceMonitor] Adb connection Error:远程主机强迫关闭了一个 ...

  8. java开发,年薪15W的你和年薪50W的他的差距

      在这个IT系统动辄就是上亿流量的时代,Java作为大数据时代应用最广泛的语言,诞生了一批又一批的新技术,包括HBase.Hadoop.MQ.Netty.SpringCloud等等 .   一些独角 ...

  9. python之函数参数问题(参数为可变对象)

    今天看到一段代码,其中函数入参有一个参数为list,类似如下: def linux_monitor(pid=0,pidlist = []): pidlist.append(pid) 通过测试发现是有问 ...

  10. 服务器运维 -- windows系统更换System32下文件后 重启无法进入桌面

    场景描述: windows系统更换System32下文件后 重启无法进入桌面 情况1,原替换文件有备份     解决建议: 准备好该文件 情况2,原备份文件没有备份  解决建议:从相同版本的服务器上边 ...