Как получить IP-адрес клиента пользователя в ASP.NET?

348

У нас есть Request.UserHostAddress, чтобы получить IP-адрес в ASP.NET, но это, как правило, IP-адрес пользователя ISP, а не только IP-адрес пользователя, который, например, нажал ссылку. Как я могу получить реальный IP-адрес?

Например, в профиле пользователя Qaru это: "Последняя активность учетной записи: 4 часа назад от 86.123.127.8" , но мой IP-адрес устройства немного отличается. Как Qaru получает этот адрес?

В некоторых веб-системах для некоторых целей есть проверка IP-адреса. Например, с определенным IP-адресом на каждые 24 часа пользователь может иметь всего 5 кликов по ссылкам загрузки? Этот IP-адрес должен быть уникальным, а не для ISP, который имеет огромный диапазон клиентов или пользователей Интернета.

Я хорошо понял?

  • 3
    Они обычно делают то же самое и не работают правильно для общих IP-адресов. В этой области мало что можно сделать.
  • 0
    Какую проблему вы пытаетесь решить здесь, почему вы думаете, что вам нужен IP-адрес?
Показать ещё 1 комментарий
Теги:
client
ip-address

16 ответов

130
Лучший ответ

Как говорили другие, вы не можете делать то, что вы просите. Если вы описываете проблему, которую пытаетесь решить, может быть, кто-то может помочь? Например. вы пытаетесь однозначно идентифицировать своих пользователей? Можете ли вы использовать файл cookie или идентификатор сеанса, а не IP-адрес?

Изменить. Адрес, который вы видите на сервере, не должен быть адресом интернет-провайдера, как вы говорите, это будет огромный диапазон. Адрес для домашнего пользователя в широкополосной сети будет адресом на своем маршрутизаторе, поэтому все устройства внутри дома будут отображаться снаружи одинаковыми, но маршрутизатор использует NAT, чтобы гарантировать, что трафик перенаправляется на каждое устройство правильно. Для пользователей, получающих доступ из офисной среды, адрес может быть одинаковым для всех пользователей. Сайты, использующие IP-адрес для идентификатора, рискуют сделать его очень неправильным - примеры, которые вы даете, хороши, и они часто терпят неудачу. Например, мой офис находится в Великобритании, точка прорыва (где я "появляюсь" в Интернете) находится в другой стране, где находится наш главный ИТ-центр, поэтому из моего офиса мой IP-адрес, похоже, не в Великобритании. По этой причине я не могу получить доступ к только веб-контенту в Великобритании, например, iPlayer BBC). В любой момент времени в моей компании будут сотни или даже тысячи людей, которые, как представляется, получают доступ к сети с одного и того же IP-адреса.

Когда вы пишете код сервера, вы никогда не можете быть уверены в том, на что ссылается IP-адрес. Некоторым пользователям это нравится. Некоторые люди намеренно используют прокси-сервер или VPN, чтобы еще больше смутить вас.

Когда вы говорите, что ваш машинный адрес отличается от IP-адреса, указанного в StackOverflow, как вы узнаете свой машинный адрес? Если вы просто смотрите локально с помощью ipconfig или что-то в этом роде, я бы ожидал, что он будет отличаться по причинам, изложенным выше. Если вы хотите проверить, что внешний мир думает, посмотрите whatismyipaddress.com/.

Эта ссылка Wikipedia на NAT предоставит вам некоторые сведения об этом.

  • 0
    поэтому я понял, что в серверных приложениях мы не можем быть уверены в IP-адресе. это означает, что программирование на стороне клиента является решением ?? Вы имеете в виду, например, с некоторыми кодами JavaScript, мы можем сделать это ??
  • 9
    НЕТ, это было бы бессмысленно, IP-адрес, который «думает» клиент, будет внутренним по отношению к дому или офису, он будет бессмысленным во внешнем мире. Например, большинство домашних маршрутизаторов раздают IP-адреса в диапазоне 192.168.1.xxx, поэтому тысячи машин имеют одинаковые адреса в своих собственных сетях.
Показать ещё 4 комментария
379

Часто вам нужно знать IP-адрес того, кто посещает ваш сайт. В то время как ASP.NET имеет несколько способов сделать это, одним из лучших способов, которые мы видели, является использование "HTTP_X_FORWARDED_FOR" коллекции ServerVariables.

Вот почему...

Иногда ваши посетители находятся за прокси-сервером или маршрутизатором, а стандартный Request.UserHostAddress только фиксирует IP-адрес прокси-сервера или маршрутизатора. В этом случае IP-адрес пользователя затем сохраняется в переменной сервера ( "HTTP_X_FORWARDED_FOR" ).

Итак, что мы хотим сделать, сначала проверьте "HTTP_X_FORWARDED_FOR" , и если это пусто, мы просто возвращаем ServerVariables("REMOTE_ADDR").

Хотя этот метод не является надежным, он может привести к лучшим результатам. Ниже приведен код ASP.NET в VB.NET, взятый из Сообщение блога Джеймса Кроули "Gotcha: HTTP_X_FORWARDED_FOR возвращает несколько IP-адресов"

С#

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
  • 0
    Привет я бегу этот код, но он всегда возвращает 127.0.0.1 ??
  • 3
    @deepeshk Вы используете его локально в IIS?
Показать ещё 12 комментариев
67

UPDATE: Благодаря Бруно Лопесу. Если может возникнуть несколько 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"];
    }
  • 3
    Как отмечено в других ответах, HTTP_X_FORWARDED_FOR может быть списком IP-адресов, разделенных запятыми.
  • 0
    В ответ на функцию я просто получаю :: 1 каждый раз. Я не могу получить полный IP-адрес ???
Показать ещё 3 комментария
24

Что еще вы считаете IP-адресом пользователя? Если вам нужен IP-адрес сетевого адаптера, я боюсь, что нет возможности сделать это в веб-приложении. Если ваш пользователь находится за NAT или другими вещами, вы также не можете получить IP.

Обновить. Хотя веб-сайты, использующие IP-адрес для ограничения пользователя (например, rapidshare), не работают корректно в средах NAT.

22

Думаю, я должен поделиться своим опытом со всеми вами. Я вижу, что в некоторых ситуациях REMOTE_ADDR НЕ доставит вам то, что вы ищете. Например, если у вас есть балансировщик нагрузки за сценой, и если вы пытаетесь получить клиентский IP-адрес, у вас будут проблемы. Я проверил его с помощью своего программного обеспечения для маскировки IP-адресов, а также проверил, что мои коллеги находятся на разных континентах. Итак, вот мое решение.

Когда я хочу узнать IP-адрес клиента, я пытаюсь выбрать все возможные доказательства, чтобы определить, являются ли они уникальными:

Здесь я нашел еще один ключ-var, который мог бы помочь вам всем, если вы хотите получить точный IP-адрес на стороне клиента. поэтому я использую: HTTP_X_CLUSTER_CLIENT_IP

HTTP_X_CLUSTER_CLIENT_IP всегда получает точный IP-адрес клиента. В любом случае, если он не дает вам значения, вы должны искать HTTP_X_FORWARDED_FOR, поскольку он является вторым лучшим кандидатом для получения вашего IP-адреса клиента, а затем REMOTE_ADDR var, который может или не может вернуть вам IP-адрес, но для меня все эти три - это то, что я нахожу лучше всего для их наблюдения.

Надеюсь, это поможет некоторым парням.

  • 0
    Надо сказать, что заголовки http_x _... могут быть легко подделаны относительно переменной remote_addr. И поэтому remote_addr остается наиболее надежным источником для IP-адреса клиента.
21

Если С# см. этот способ, очень просто

string clientIp = (Request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? 
                   Request.ServerVariables["REMOTE_ADDR"]).Split(',')[0].Trim();
  • 7
    Если обе серверные переменные могут быть нулевыми, это может вызвать исключение.
15

Вы можете использовать:

System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList.GetValue(0).ToString();
  • 1
    спасибо, для меня это единственный метод, который действительно возвращает мой IP на локальном хосте.
  • 0
    На самом деле я использовал для получения IP-адреса локального хоста System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList[1].ToString();
Показать ещё 2 комментария
14

IP-адреса являются частью сетевого уровня в "семислойном стеке". Сетевой уровень может делать все, что он хочет сделать с IP-адресом. То, что происходит с прокси-сервером, NAT, реле и т.д.

Уровень приложения не должен зависеть от IP-адреса. В частности, IP-адрес не должен быть идентификатором чего-либо иного, кроме idenfitier одного конца сетевого соединения. Как только соединение будет закрыто, вы должны ожидать, что IP-адрес (того же пользователя) изменится.

  • 0
    Это все хорошо, но что вы делаете, когда один клиент мультитенантной системы требует, чтобы учетные записи его пользователей могли входить только с указанного IP-адреса?
  • 1
    Затем они должны сказать вам, какой IP-адрес увидит ваш сервер. Если им нужен конкретный адрес, они не смогут находиться за NAT или чем-то подобным.
9

Если вы используете 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();
  • 0
    И используя F5 или Пало-Альто?
8
string IP = HttpContext.Current.Request.Params["HTTP_CLIENT_IP"] ?? HttpContext.Current.Request.UserHostAddress;
  • 0
    это будет работать для WebAPI 2.x?
7

Все ответы до сих пор учитывают нестандартизированный, но очень распространенный заголовок X-Forwarded-For. Существует стандартизированный заголовок Forwarded который немного сложнее разобрать. Вот некоторые примеры:

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;
        }
    }
}

Ниже приведены некоторые модульные тесты, которые я использовал для проверки своего решения:

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; }
        }
    }
}
7

Что вы можете сделать, это сохранить IP-адрес маршрутизатора вашего пользователя, а также перенаправленный IP-адрес и попытаться сделать его надежным, используя оба IP-адреса [External Public и Internal Private]. Но через несколько дней клиенту может быть назначен новый внутренний IP-адрес от маршрутизатора, но он будет более надежным.

3

Комбинируя ответы @Tony и @mangokun, я создал следующий метод расширения:

public static class RequestExtensions
{
    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)
        {
            string ipAddress = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

            if (!string.IsNullOrEmpty(ipAddress))
            {
                string[] addresses = ipAddress.Split(',');
                if (addresses.Length != 0)
                {
                    return addresses[0];
                }
            }
        }

        return Request.UserHostAddress;
    }
}
  • 0
    Почему вы используете HTTP_X_FORWARDED_FOR а не X_FORWARDED_FOR ? Они одинаковы?
  • 0
    они такие же ...
3

использовать в файле 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"];
}
-2

используйте этот

Dns.GetHostEntry(Dns.GetHostName())
  • 4
    Dns.GetHostEntry Метод GetHostEntry запрашивает у DNS-сервера IP-адрес, связанный с именем хоста или IP-адресом. См. Msdn.microsoft.com/en-us/library/ms143998(v=vs.80).aspx
-7

Пытаться:

using System.Net;

public static string GetIpAddress()  // Get IP Address
{
    string ip = "";     
    IPHostEntry ipEntry = Dns.GetHostEntry(GetCompCode());
    IPAddress[] addr = ipEntry.AddressList;
    ip = addr[2].ToString();
    return ip;
}
public static string GetCompCode()  // Get Computer Name
{   
    string strHostName = "";
    strHostName = Dns.GetHostName();
    return strHostName;
}
  • 0
    Почему за это проголосовали?
  • 0
    Это возвращает IP-адрес сервера
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню