ip адрес в asp.net

Несколько мыслей о получении IP адреса клиента в ASP.NET - .NetBlog - блог о программировании на C# .Net, и других, не мене интересных вещах.

суббота, 6 декабря 2014 г.

Несколько мыслей о получении IP адреса клиента в ASP.NET

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

Итак, самый широко известный в мире ASP.NET способ получения IP-адреса клиента - это использование HttpContext.Current.Request.UserHostAddress, который, по сути является оберткой над HTTP заголовком REMOTE_ADDR, в которую записывается адрес хоста от которого серверу пришел запрос. А этот заголовок используется практически во всех языках программирования, для целей определения IP клиента. И везде не утихают споры правильно ли использовать именно его. Почему? Потому, что REMOTE_ADDR содержит адрес компьютера, установившего соединение с сервером. Во времена становления интернет и появления протокола HTTP этик компьютером почти наверняка являлся клиент, так что все было хорошо. Сейчас же, в большинстве случаев, в REMOTE_ADDR будет адрес прокси сервера внутренней сети (корпоративной, или домашней - смысла это не меняет) через который прошел запрос клиента.
И еще один пример, с которым, особенно часто сталкиваются Linux программисты, в результате криво настроенного nginx. ;)
Представьте себе ситуацию, что у вас есть криво настроенный балансировщик нагрузки. В таком случае в REMOTE_ADDR будет 10.10.0.2, что, естественно совершенно не клиентский адрес.




В общем-то именно из-за этих двух моментов, касающихся REMOTE_ADDR, многие рекомендуют использовать для целей получения адреса клиента другой заголовок - HTTP_X_FORWARDED_FOR, придуманный в свое время создателями кеширующего прокси-сервера Squid.
Этот заголовок, в идеале, должен содержать всю цепочку IP-адресов от клиента до вашего сервера, перечисленных через запятую. Почему в идеале? Потому, что, во-первых, этот заголовок передается самим клиентом, то есть, в него можно записать все что угодно, например "la-la-la", в результате чего, если между злодейским клиентгм и вашим сервером один прокси,
HTTP_X_FORWARDED_FOR будет содержать что-то типа:

la-la-la, 192.168.0.10

Так что, как вы наверное догадались, использовать этот заголовок так, как часто рекомендуют в интернетах нельзя. Забудьте про этот вариант:

 
    if (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
    {
        return HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
    }

Во-первых, там может быть что угодно, а не обязательно IP-адрес. А во-вторых, потому, что содержать реальный IP-адрес клиента в чистом виде этот заголовок будет только в случае если между клиентом и вами всего один прокси и клиент имеет нормальный полноценный IP.

В 99.9% случае это будет адрес из приватной подсети 192.168.*.* Так что, если уж вы решили использовать HTTP_X_FORWARDED_FOR, то, как минимум, проверяйте что там вообще IP-адрес и из какого он IP-диапазона.

 
         string ipAddr = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();

         if (Regex.IsMatch(ipAddr,"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"))
         {
             if (!(ipAddr.StartsWith("192.168.")||(ipAddr.StartsWith("10.")))

             {
                return ipAddr;
             }
         }
         return HttpContext.Current.Request.UserHostAddress;

Если же HTTP_X_FORWARDED_FOR cодержит несколько адресов, то рекомендую использовать второй, так как первый адрес практически гарантированно будет из внутренней подсети. Ну и, естественно, не забываем проверять содержимое.
 
    string ipAddr = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
    if (!string.IsNullOrEmpty(ipAddr))
    {
        string[] addresses = ipAddr.Split(',');
        if (addresses.Length == 1)
        {
            ipAddr = addresses[0];
        }
        else if (addresses.Length >1)
        {
                   ipAddr = addresses[1];
        }
        if (Regex.IsMatch(ipAddr,"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"))
        {
            if (!(ipAddr.StartsWith("192.168.")||(ipAddr.StartsWith("10.")))) 
            {
                return ipAddr;
            }
        }
    }
    return HttpContext.Current.Request.UserHostAddress;

Так что, именно вот такой код, по моему мнению, является наиболее правильным вариантом определения IP адреса клиента. Хотя, как мне кажется, в большинстве случаев, все же вполне достаточно Request.UserHostAddress или Request.ServerVariables["REMOTE_ADDR"].

Ну а в случае, если вы получаете IP клиента из соображений безопасности, например для проверки валидности сессии, то самым правильным в таком случае будет самое простое решение - сравнивать все, что есть, например в виде простой строки:
 
    string ipAddrForSecurity = HttpContext.Current.Request.UserHostAddress+HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();


Комментариев нет:

Отправить комментарий

Комментарии

  1. As reported by Stanford Medical, It is in fact the ONLY reason women in this country live 10 years longer and weigh 42 lbs less than us.

    (And really, it is not related to genetics or some secret-exercise and EVERYTHING to do with "HOW" they eat.)

    P.S, I said "HOW", not "WHAT"...

    CLICK this link to find out if this short quiz can help you unlock your true weight loss possibilities

    ОтветитьУдалить

Отправить комментарий