В ASP.NET Ядро как вы проверяете, является ли запрос локальным?

#c# #asp.net-core

#c# #asp.net-ядро

Вопрос:

В обычном ASP.NET вы могли бы сделать это в представлении, чтобы определить, был ли текущий запрос от localhost:

HttpContext.Current.Request.IsLocal

Но я не могу найти что-то подобное в ASP.NET 6/Ядро/ как бы оно ни называлось.

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

1. Будьте осторожны с использованием HttpContext.Connection.IsLocal . Мне кажется, что использование HttpContext.Connection.RemoteIpAddress является более безопасным способом . Если я подключусь к тестированию ASP.NET 5 Проект RC1 локально я вижу ::1 в RemoteIpAddress , но HttpContext.Connection.IsLocal есть false . Это неправильно.

2. Приветствую Олег, то, что вы сказали, оказалось правдой и для меня.

3. Я тоже получаю такое же поведение. Это всегда false локально.

Ответ №1:

ОБНОВЛЕНИЕ: ASP.NET В ядре 2.0 есть метод с именем Url.IsLocalUrl (см. Этот документ Microsoft Docs).

Я думаю, что этот код будет работать, но я не смог протестировать его полностью

 var callingUrl = Request.Headers["Referer"].ToString();
var isLocal = Url.IsLocalUrl(callingUrl);
 

Но смотрите Комментарий Уилла Дина ниже об этом подходе:

Любой, кто думает об использовании «обновленной» версии, которая проверяет заголовок ссылки, должен иметь в виду, что заголовки чрезвычайно легко подделать до такой степени, что это не относится к IP-адресам с обратной связью.


Оригинальное решение

Я наткнулся на это в поисках решения, позволяющего узнать, является ли запрос локальным. К сожалению ASP.NET версия 1.1.0 не имеет IsLocal метода для подключения. Я нашел одно решение на веб-сайте под названием Strathweb, но оно тоже устарело.

Я создал свое собственное IsLocal расширение, и оно, кажется, работает, но я не могу сказать, что тестировал его во всех обстоятельствах, но вы можете попробовать.

 public static class IsLocalExtension
{
    private const string NullIpAddress = "::1";

    public static bool IsLocal(this HttpRequest req)
    {
        var connection = req.HttpContext.Connection;
        if (connection.RemoteIpAddress.IsSet())
        {
            //We have a remote address set up
            return connection.LocalIpAddress.IsSet() 
                  //Is local is same as remote, then we are local
                ? connection.RemoteIpAddress.Equals(connection.LocalIpAddress) 
                  //else we are remote if the remote IP address is not a loopback address
                : IPAddress.IsLoopback(connection.RemoteIpAddress);
        }

        return true;
    }

    private static bool IsSet(this IPAddress address)
    {
        return address != null amp;amp; address.ToString() != NullIpAddress;
    }
}
 

Вы вызываете его в действии контроллера, используя Request свойство, т.е.

  public IActionResult YourAction()
 {
     var isLocal = Request.IsLocal();
     //... your code here
 }
 

Я надеюсь, что это кому-то поможет.

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

1. Это помогло мне. Вот моя версия.

2. Любой, кто думает об использовании «обновленной» версии, которая проверяет заголовок ссылки, должен иметь в виду, что заголовки чрезвычайно легко подделать, до такой степени, что это не относится к IP-адресам с обратной связью.

3. Заголовок Referer запроса не имеет никакого отношения к тому, является ли удаленный IP-адрес локальным или нет.

Ответ №2:

На момент написания HttpContext.Connection.IsLocal в настоящее время отсутствует в .NET Core.

Другое рабочее решение проверяет только первый адрес обратной связи ( ::1 или 127.0.0.1 ), который может быть неадекватным.

Я нахожу приведенное ниже решение полезным:

 using Microsoft.AspNetCore.Http;
using System.Net;

namespace ApiHelpers.Filters
{
    public static class HttpContextFilters
    {
        public static bool IsLocalRequest(HttpContext context)
        {
            if (context.Connection.RemoteIpAddress.Equals(context.Connection.LocalIpAddress))
            {
                return true;
            }
            if (IPAddress.IsLoopback(context.Connection.RemoteIpAddress))
            {
                return true;
            }
            return false;
        }
    }
}
 

И пример использования:

 app.UseWhen(HttpContextFilters.IsLocalRequest, configuration => configuration.UseElmPage());
 

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

1. Этот метод можно упростить до public static bool IsLocalRequest(HttpContext context) => context.Connection.RemoteIpAddress.Equals(context.Connection.LocalIpAddress) || IPAddress.IsLoopback(context.Connection.RemoteIpAddress); .

2. Разве 2-й if не должен читать if (IPAddress.IsLoopback(context.Connection.LocalIpAddress)) вместо использования RemoteIpAdress ?

3. Я не думаю, что это имеет значение на практике, функция может возвращать false, если кто-то устанавливает соединение с адресом внешнего интерфейса из loopback или наоборот, но это не то, что происходит по умолчанию, поэтому любой IP-адрес из диапазона 127 или IPv6 будет принят независимо от того, является ли он удаленным контрольный или местный. Кроме того, поскольку проверка касается удаленного подключения к серверу, проверка удаленного адреса лучше подходит для этой цели.

4. Можно ли это подделать?

Ответ №3:

Для меня ничего из вышеперечисленного не сработало.

Url.IsLocalUrl работает совсем по-другому, и я нахожу это немного бесполезным:

Например, следующие URL-адреса считаются локальными:

   /Views/Default/Index.html
  ~/Index.html
 

Следующие URL-адреса являются нелокальными:

   ../Index.html
  http://www.contoso.com/
  http://localhost/Index.html
 

HttpContext.Connection.IsLocal не существует в .Net Core 2.2

Сравнение ControllerContext.HttpContext.Connection.RemoteIpAddress и ControllerContext.HttpContext.Connection.LocalIpAddress также не работает в моем тесте, потому что я получаю «:: 1» для удаленного ip и «127.0.0.1» для локального ip.

Наконец, я использовал эту часть:

 IPAddress addr = System.Net.IPAddress.Parse( HttpContext.Connection.RemoteIpAddress.ToString() );
if (System.Net.IPAddress.IsLoopback(addr) )
{
    //do something
}
 

Ответ №4:

Поздно на вечеринку, но если я хочу проверить IsLocal в представлениях razor.Net core 2.2 , я просто делаю это:

 @if (Context.Request.Host.Value.StartsWith("localhost"))
{
    //do local stuff
}
 

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

1. Это очень уродливый способ сделать это. Что, если у вас есть сайт под названием localhost.site.com ? Или даже localhosting.com .

Ответ №5:

ОБНОВЛЕНИЕ для ASP.NET Ядро 3.1

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

 if (Request.Host.Host == "localhost") {// do something }
 

Ответ №6:

Я также хотел бы упомянуть, что может быть полезно добавить предложение ниже в конец вашей пользовательской IsLocal() проверки

 if (connection.RemoteIpAddress == null amp;amp; connection.LocalIpAddress == null)
{
    return true;
}
 

Это учитывало бы сценарий, в котором сайт запускается с использованием Microsoft.AspNetCore.TestHost , и сайт запускается полностью локально в памяти без фактического TCP / IP-соединения.

Ответ №7:

теперь его

 HttpContext.Connection.IsLocal
 

и если вам нужно проверить это вне контроллера, тогда вы получаете зависимость IHttpContextAccessor , чтобы получить к нему доступ.

Обновление на основе комментариев:

HttpContext внутренне доступен в представлениях

 @if (Context.Connection.IsLocal)
{

}
 

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

1. Я беру зависимость в представлении, делая это @inject IHttpContextAccessor Context; правильно? Текущее значение local всегда равно false…

2. Это уходит в RC2. У Филипа здесь есть альтернативный подход: strathweb.com/2016/04/request-islocal-in-asp-net-core но даже это, похоже, сильно зависит от другого промежуточного программного обеспечения и от того, какой сервер вы используете.