Всем привет, сегодня расскажу про host filtering в C#

Сразу к делу, расскажу, как это сделать, а потом уже, зачем это и остальное, так как статья ориентирована на тех, кто уже знает, зачем им это. Всё будет демонстрироваться на новом проекте в visual studio, .NET 8

Подготовка проекта

Выбираем проект веб апи --> настраиваем сам проект и дополнительные сведения

Для наглядного примера по пути C:\Windows\System32\drivers\etc\hosts я добавил новый домен, чтобы показать, что запрос будет с разных доменов

C:\Windows\System32\drivers\etc\hosts
C:\Windows\System32\drivers\etc\hosts

Настройка - вариант 1

Через appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

В 8 строчке вместо звездочки добавьте нужные домены через точку с запятой

Пример:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "localhost;globalhost"// или "AllowedHosts": "localhost" для одного домена
}

Настройка - вариант 2.1

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<HostFilteringOptions>(options =>
{
    options.AllowedHosts.Clear();
    options.AllowedHosts.Add("localhost");
    options.AllowedHosts.Add("globalhost");
    options.AllowedHosts.Add("openclawai.website"); // Отсылка на наш сайт?
});

Настройка - вариант 2.2

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHostFiltering(options =>
{
    options.AllowedHosts = new List<string> { "localhost", "globalhost" };

    options.AllowEmptyHosts = false; // запретить запросы без Host header (HTTP/1.0)
    options.IncludeFailureMessage = true;  // true по умолчанию, в 400 ответе показывает, что Host не прошёл
});

Что получаем (при варианте 2.2)

Обращение к разрешенному хосту (аналогично с localhost)
Обращение к разрешенному хосту (аналогично с localhost)

Как видим, мы получаем данные при обращении к разрешенным хостам

Обращение к запрещенному хосту (аналогично с localhost)
Обращение к запрещенному хосту (аналогично с localhost)

А тут уже Bad Request

Зачем все же это нужно?

  1. Kestrel работает напрямую в интернете (без обратного прокси)

  2. Приложение за reverse-прокси, но прокси передаёт оригинальный Host

  3. Docker / Kubernetes, приложение доступно по IP или через Ingress без перезаписи Host

  4. Multi-tenant SaaS (tenant1.app.com, tenant2.app.com)

  5. Используется HTTP/2 или gRPC на Kestrel

Host filtering помогает справиться с Password Reset Poisoning, Cache Poisoning через CDN, DNS Rebinding + SSRF-подобная

Итог

Это моя первая статья, относительно долго её писал, думал, что исправить, что добавить, а что нет, опыта у меня в этом мало, спасибо за прочтение!

P.S.: если у вас есть коммерческое предложение ко мне (предложение о работе к примеру), то пишите в лс, рад буду пообщаться