如何在ASP.NET中获取用户的客户端IP地址?

我们有Request.UserHostAddress来获取ASP.NET中的IP地址,但这通常是用户的ISP的IP地址,而不是用户的机器IP地址,例如点击链接。 我怎样才能得到真正的IP地址?

例如,在Stack Overflow用户configuration文件中,它是: “Last account activity:4 hours ago from 86.123.127.8” ,但是我的机器IP地址有些不同。 堆栈溢出如何得到这个地址?

在某些networking系统中,出于某种目的而进行IP地址检查。 例如,对于某个IP地址,每24小时用户只能点击5次下载链接? 此IP地址应该是唯一的,不适用于拥有大量客户端或Internet用户的ISP。

我理解得好吗?

正如别人所说,你不能做你所问的。 如果你描述你正在努力解决的问题,也许有人可以帮忙? 例如,你是否试图唯一标识你的用户? 你可以使用cookie,或者会话ID而不是IP地址?

编辑你在服务器上看到的地址不应该是ISP的地址,如你所说那将是一个巨大的范围。 宽带家庭用户的地址将是其路由器的地址,因此房屋内的每台设备都将出现在外部,因此路由器使用NAT来确保将stream量正确路由到每个设备。 对于从办公室环境访问的用户而言,所有用户的地址可能是相同的。 使用IP地址作为ID的站点有可能导致错误 – 您提供的示例很好,而且经常失败。 例如,我的办公室在英国,我的主要IT设施位于另一个国家,因此从我的办公室,我的IP地址似乎不在英国,突破点(我“出现”在互联网上)。 出于这个原因,我不能访问英国唯一的networking内容,如BBC iPlayer)。 在任何时候,我的公司中会有数百甚至数千人似乎是从相同的IP地址访问networking。

当你编写服务器代码时,你永远不能确定你所看到的IP地址是指什么。 有些用户喜欢这种方式。 有些人故意使用代理或VPN来进一步混淆你。

当你说你的机器地址与StackOverflow上显示的IP地址不同时,你如何find你的机器地址? 如果你只是在本地使用ipconfig或类似的东西,我会期望它是不同的,因为我上面概述的原因。 如果你想仔细检查一下外界的想法,请看whatismyipaddress.com/ 。

这个关于NAT的维基百科链接将为您提供一些背景知识。

通常你会想知道访问你的网站的人的IP地址。 虽然ASP.NET有几种方法可以做到这一点,但我们所看到的最好的方法之一就是使用ServerVariables集合的“HTTP_X_FORWARDED_FOR”。

这是为什么…

有时您的访问者位于代理服务器或路由器之后,标准的Request.UserHostAddress仅捕获代理服务器或路由器的IP地址。 当这种情况下,用户的IP地址被存储在服务器variables(“HTTP_X_FORWARDED_FOR”)中。

所以我们想要做的是首先检查“HTTP_X_FORWARDED_FOR”,如果是空的,我们只需返回ServerVariables("REMOTE_ADDR")

虽然这种方法不是万无一失的,但可以带来更好的结果。 下面是VB.NET中的ASP.NET代码,取自James Crowley的博客文章“Gotcha:HTTP_X_FORWARDED_FOR返回多个IP地址”

C#

 protected string GetIPAddress() { System.Web.HttpContext context = System.Web.HttpContext.Current; string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrEmpty(ipAddress)) { string[] addresses = ipAddress.Split(','); if (addresses.Length != 0) { return addresses[0]; } } return context.Request.ServerVariables["REMOTE_ADDR"]; } 

VB.NET

 Public Shared Function GetIPAddress() As String Dim context As System.Web.HttpContext = System.Web.HttpContext.Current Dim sIPAddress As String = context.Request.ServerVariables("HTTP_X_FORWARDED_FOR") If String.IsNullOrEmpty(sIPAddress) Then Return context.Request.ServerVariables("REMOTE_ADDR") Else Dim ipArray As String() = sIPAddress.Split(New [Char]() {","c}) Return ipArray(0) End If End Function 

更新:感谢布鲁诺洛佩斯。 如果有几个IP地址可以使用,那么需要使用这个方法:

  private string GetUserIP() { string ipList = Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrEmpty(ipList)) { return ipList.Split(',')[0]; } return Request.ServerVariables["REMOTE_ADDR"]; } 

还有什么你认为用户的IP地址? 如果您想要networking适配器的IP地址,恐怕没有办法在Web应用程序中执行此操作。 如果你的用户在NAT或其他东西后面,你也不能得到IP。

更新 :虽然有网站使用IP来限制用户(如rapidshare),但它们在NAT环境中无法正常工作。

我想我应该和大家分享我的经验。 那么我在某些情况下看到REMOTE_ADDR不会得到你正在寻找的东西。 例如,如果您在场景后面有负载平衡器,并且您正在尝试获取客户端的IP,那么您将遇到麻烦。 我用我的IP掩模软件检查了它,再加上我在不同大陆的同事进行了检查。 所以这是我的解决scheme。

当我想知道客户的知识产权时,我会尽量挑选一切可能的证据,以便确定它们是否独一无二:

在这里,我发现了另一个sever-var,如果你想获得客户端的确切IP,可以帮助你。 所以我正在使用: HTTP_X_CLUSTER_CLIENT_IP

HTTP_X_CLUSTER_CLIENT_IP总是让你的客户端的确切的IP。 在任何情况下,如果它没有给你的价值,你应该寻找HTTP_X_FORWARDED_FOR,因为它是第二个最好的候选人,让你的客户端IP,然后REMOTE_ADDR var可能会或可能不会返回你的IP,但对我有所有这些三是我觉得最好的事情来监视他们。

我希望这可以帮助一些人。

如果是c#这样看,很简单

 string clientIp = (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? Request.ServerVariables["REMOTE_ADDR"]).Split(',')[0].Trim(); 

IP地址是“七层堆叠”中networking层的一部分。 networking层可以做​​任何想做的IP地址。 这就是代理服务器,NAT,中继或其他什么情况。

应用层不应以任何方式依赖IP地址。 特别地,IP地址并不意味着除了networking连接的一端的标识符以外的任何标识符。 一旦连接closures,您应该期望(同一个用户的)IP地址改变。

您可以使用:

 System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList.GetValue(0).ToString(); 
 string IP = HttpContext.Current.Request.Params["HTTP_CLIENT_IP"] ?? HttpContext.Current.Request.UserHostAddress; 

如果你正在使用CloudFlare,你可以试试这种扩展方法

 public static class IPhelper { public static string GetIPAddress(this HttpRequest Request) { if (Request.Headers["CF-CONNECTING-IP"] != null) return Request.Headers["CF-CONNECTING-IP"].ToString(); if (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null) return Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString(); return Request.UserHostAddress; } } 

然后

 string IPAddress = Request.GetIPAddress(); 

你可以做的是存储你的用户的路由器IP,以及转发的IP,并尝试使用这两个IP [外部公共和内部私人]的可靠性。 但是有一段时间之后客户端可能会从路由器分配新的内部IP,但是它会更可靠。

在ashx文件中使用

 public string getIP(HttpContext c) { string ips = c.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrEmpty(ips)) { return ips.Split(',')[0]; } return c.Request.ServerVariables["REMOTE_ADDR"]; } 

到目前为止,所有的反应都考虑到了非标准化的X-Forwarded-For头。 有一个标准化的Forwarded头,这是一个更难以parsing。 一些例子如下:

 Forwarded: for="_gazonk" Forwarded: For="[2001:db8:cafe::17]:4711" Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43 Forwarded: for=192.0.2.43, for=198.51.100.17 

我已经写了一个类,在确定客户端的IP地址时考虑了这两个头文件。

 using System; using System.Web; namespace Util { public static class IP { public static string GetIPAddress() { return GetIPAddress(new HttpRequestWrapper(HttpContext.Current.Request)); } internal static string GetIPAddress(HttpRequestBase request) { // handle standardized 'Forwarded' header string forwarded = request.Headers["Forwarded"]; if (!String.IsNullOrEmpty(forwarded)) { foreach (string segment in forwarded.Split(',')[0].Split(';')) { string[] pair = segment.Trim().Split('='); if (pair.Length == 2 && pair[0].Equals("for", StringComparison.OrdinalIgnoreCase)) { string ip = pair[1].Trim('"'); // IPv6 addresses are always enclosed in square brackets int left = ip.IndexOf('['), right = ip.IndexOf(']'); if (left == 0 && right > 0) { return ip.Substring(1, right - 1); } // strip port of IPv4 addresses int colon = ip.IndexOf(':'); if (colon != -1) { return ip.Substring(0, colon); } // this will return IPv4, "unknown", and obfuscated addresses return ip; } } } // handle non-standardized 'X-Forwarded-For' header string xForwardedFor = request.Headers["X-Forwarded-For"]; if (!String.IsNullOrEmpty(xForwardedFor)) { return xForwardedFor.Split(',')[0]; } return request.UserHostAddress; } } } 

下面是我用来validation我的解决scheme的一些unit testing:

 using System.Collections.Specialized; using System.Web; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace UtilTests { [TestClass] public class IPTests { [TestMethod] public void TestForwardedObfuscated() { var request = new HttpRequestMock("for=\"_gazonk\""); Assert.AreEqual("_gazonk", Util.IP.GetIPAddress(request)); } [TestMethod] public void TestForwardedIPv6() { var request = new HttpRequestMock("For=\"[2001:db8:cafe::17]:4711\""); Assert.AreEqual("2001:db8:cafe::17", Util.IP.GetIPAddress(request)); } [TestMethod] public void TestForwardedIPv4() { var request = new HttpRequestMock("for=192.0.2.60;proto=http;by=203.0.113.43"); Assert.AreEqual("192.0.2.60", Util.IP.GetIPAddress(request)); } [TestMethod] public void TestForwardedIPv4WithPort() { var request = new HttpRequestMock("for=192.0.2.60:443;proto=http;by=203.0.113.43"); Assert.AreEqual("192.0.2.60", Util.IP.GetIPAddress(request)); } [TestMethod] public void TestForwardedMultiple() { var request = new HttpRequestMock("for=192.0.2.43, for=198.51.100.17"); Assert.AreEqual("192.0.2.43", Util.IP.GetIPAddress(request)); } } public class HttpRequestMock : HttpRequestBase { private NameValueCollection headers = new NameValueCollection(); public HttpRequestMock(string forwarded) { headers["Forwarded"] = forwarded; } public override NameValueCollection Headers { get { return this.headers; } } } } 

用这个

 Dns.GetHostEntry(Dns.GetHostName())