Налаштування заголовків перенаправлення в .NET при роботі з Azure Application Gateway
Коли ми розгортаємо .NET додаток на Azure App Service
та налаштовуємо доступ до нього через Azure Application Gateway
, виникає типова проблема з визначенням правильного хосту та схеми запиту. Суть проблеми в тому, що запит проходить кілька рівнів до вашого додатка:
- Користувач відправляє запит на
https://myapp.example.com
- Запит потрапляє до
Application Gateway
Application Gateway
перенаправляє запит доApp Service
App Service
передає запит вашому додатку
На кожному етапі інформація про оригінальний запит (IP-адреса користувача, схема, хост) може бути втрачена або замінена на внутрішню. В результаті, коли запит досягає вашого додатка, HttpContext
містить не ті дані, які були в оригінальному запиті. Наприклад, якщо ваш користувач заходить через https://myapp.example.com
, то до вашого додатка запит може дійти як http://internal-appservice-ip:port
. Це призводить до таких проблем:
- Неправильна генерація URL - всі посилання, які генерує ваш додаток, будуть містити неправильний хост та схему
- Помилки автентифікації - особливо з
OpenIddict
або іншими реалізаціямиOpenID Connect
, які суворо перевіряють URL перенаправлення - Проблеми з
CORS
- неправильне визначення Origin-заголовка - Помилки в роботі
middleware
- багато компонентів .NET залежать від правильного визначення схеми та хоста
Рішення
.NET має вбудований механізм для обробки перенаправлених заголовків, який можна налаштувати для коректної роботи з проксі-серверами.
Нижче наведено код, який вирішує проблему:
1
2
3
4
5
6
7
8
9
10
11
12
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto |
ForwardedHeaders.XForwardedHost;
options.ForwardedHostHeaderName = "X-Original-Host";
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
Розберемо, що відбувається в цьому коді:
Налаштування ForwardedHeaders
1
2
3
4
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto |
ForwardedHeaders.XForwardedHost;
Тут ми вказуємо, які саме заголовки перенаправлення повинні оброблятися:
XForwardedFor
- визначає оригінальну IP-адресу клієнтаXForwardedProto
- визначає оригінальний протокол (http або https)XForwardedHost
- визначає оригінальний хост, вказаний у запиті
Налаштування додаткового заголовка хосту
1
options.ForwardedHostHeaderName = "X-Original-Host";
Цей рядок є критично важливим для нашого сценарію з Azure Application Gateway
. Він вказує .NET дивитися на нестандартний заголовок X-Original-Host
для визначення оригінального хосту. Часто Azure Application Gateway
або інші проксі налаштовані на передачу оригінального хосту саме в цьому заголовку замість стандартного X-Forwarded-Host
.
Очищення списків довірених мереж і проксі
1
2
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
За замовчуванням, .NET приймає перенаправлені заголовки тільки від довірених проксі для безпеки. Очищаючи ці списки, ми дозволяємо приймати заголовки від будь-яких джерел.
Приклад проблеми з OpenIddict
Розглянемо конкретний приклад проблеми з OpenIddict
:
Припустимо, ваш додаток розгорнуто за Application Gateway
, і користувачі отримують доступ до нього за адресою https://myapp.example.com
. Однак, сам додаток бачить запити, що надходять від Application Gateway
з локальної мережі, наприклад, як http://internal-ip:port
. При налаштуванні OpenIddict
, ви вказуєте URL перенаправлення як https://myapp.example.com/signin-callback
. Коли користувач проходить автентифікацію, OpenIddict
намагається перевірити, чи збігається URL перенаправлення з налаштованим. Але оскільки додаток “думає”, що працює за адресою http://internal-ip:port
, він генерує URL перенаправлення як http://internal-ip:port/signin-callback
.
Результат: несумісність URL призводить до помилки автентифікації з повідомленням на кшталт "Invalid redirect_uri"
.
Застосування рішення в Startup.cs
Для повного вирішення проблеми, крім налаштування опцій, необхідно також додати middleware для обробки перенаправлених заголовків у метод Configure:
1
2
// Важливо додати це на самому початку пайпайна обробки запитів
app.UseForwardedHeaders();
Особливості налаштування для Azure App Service
Додатково варто зазначити, що коли ваш додаток розгорнуто на Azure App Service
за Application Gateway
, проблема з перенаправленням заголовків стає особливо актуальною. App Service
має власну інфраструктуру балансування навантаження, яка додає ще один рівень проксіювання:
Користувач → Application Gateway → App Service infrastructure → Ваш додаток
Кожен рівень може модифікувати заголовки, тому правильне налаштування ForwardedHeadersOptions
є критичним для забезпечення коректної роботи додатка в такій архітектурі. Також при розгортанні на App Service
рекомендується перевірити налаштування ssl termination
. Якщо SSL-термінація відбувається на рівні Application Gateway
, то до вашого додатка запити можуть надходити по HTTP
, навіть якщо клієнт використовує HTTPS. У такому випадку правильна обробка XForwardedProto
забезпечить коректне визначення схеми.
Висновок
Правильне налаштування перенаправлених заголовків є критично важливим при розгортанні .NET додатків на Azure App Service
за проксі-серверами, особливо якщо ви використовуєте протоколи автентифікації, такі як OpenID Connect
. Наведене рішення дозволяє додатку коректно визначати оригінальну адресу запиту, що забезпечує правильну роботу URL-генерації, автентифікації та інших компонентів, які залежать від точного визначення хоста та схеми запиту.
Не забудьте в реальному сценарії налаштувати список довірених проксі для підвищення безпеки вашого додатку.