Як сконфігурувати Symfony, щоб вона працювала за розподільником навантаження або зворотним проксі

Дата оновлення перекладу 2024-05-27

Як сконфігурувати Symfony, щоб вона працювала за розподільником навантаження або зворотним проксі

Коли ви розгортаєте свій додаток, ви можете знаходитися за розподільником навантаження (наприклад, еластичне розподілення навантаження AWS) або зворотним проксі (наприклад, Varnish для кешування).

У більшості випадків це не викликає проблем з Symfony. Але коли запит проходить через проксі, відправдяється певна інформація запиту, використовуючи або стандартний заголовок Forwarded, або заголовки X-Forwarded-*. Наприклад, замість читання заголовку REMOTE_ADDR (який тепер буде IP-адресою вашого зворотного проксі), справжній IP користувача зберігатиметься у стандартному заголовку Forwarded: for="..." або заголовку X-Forwarded-For.

Якщо ви не сконфігуруєте Symfony так, щоб вона шукала такі заголовки, то ви отримуватимете неправильну інфорамцію про IP-адресу клієнта, незалежно від того, чи підключається він через HTTPS, чи ні, клієнтського порту та запитуваного імені хосту.

Вирішення: setTrustedProxies()

Щоб виправити це, вам потрібно сказати Symfony, яким IP-адресам зворотного проксі можна довіряти, і які заголовки використовує ваш проксі для відправки інформації:

1
2
3
4
5
6
7
8
9
# config/packages/framework.yaml
framework:
    # ...
    # IP-адреса (або діапазон) вашого проксі
    trusted_proxies: '192.0.0.1,10.0.0.0/8'
    # довіряти *всім* заголовкам "X-Forwarded-*"
    trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix']
    # або, якщо ваш проксі замість цього використовує заголовок "Forwarded"
    trusted_headers: ['forwarded']

7.1

private_ranges як ярлик для приватних діапазонів IP-адрес для опції trusted_proxies було представлено у Symfony 7.1.

Caution

Включення опції Request::HEADER_X_FORWARDED_HOST робить додаток вразливим до атак заголовків хостингу HTTP. Переконайтеся в тому, що прооксі дійсно відправляє заголловок x-forwarded-host.

Обʼєкт Запит має декілька констант Request::HEADER_*, які контролюють, яким заголовкам вашого зворотного проксі можна довіряти. Аргумент є полем біту, так що ви також можете передати власне значення (наприклад, 0b00110).

Tip

Ви можете встановити змінну середовища TRUSTED_PROXIES, щоб конфігурувати проксі, засновуючись на середовищі:

1
2
# .env
TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8
1
2
3
4
# config/packages/framework.yaml
framework:
    # ...
    trusted_proxies: '%env(TRUSTED_PROXIES)%'

Danger

Функція "довірені проксі" не працює, як очікується, при використанні модуля nginx realip. Відключіть цей модуль при обслуговуванні додатків Symfony.

Але що, якщо IP мого зворотнго проксі постійно змінюється!

Деякі зворотні проксі (на кшталт Еластичного розподілення навантаження AWS) не мають статичної IP-адреси або навіть діапазону, який ви можете охопити за допомогою CIDS примітки. В такому випадку вам потрібно буде - дуже обережно - довіряти всім проксі.

  1. Сконфігуруйте ваш(і) веб-сервер(и), щоб вони не відповідали на трафік будь-яких клієнтів, окрім ваших розподілювачів навантаження. Для AWS це можна зробити за допомогою груп безпеки.
  2. Коли ви гарантували, що трафік буде виходити лише від довірених зворотних проксі, сконфігуруйте Symfony завжди довіряти вхідному запиту:

    1
    2
    3
    4
    5
    6
    # config/packages/framework.yaml
    framework:
        # ...
        # довіряти *всім* запитам (рядок 'REMOTE_ADDR' замінюється під час
        # прогону на $_SERVER['REMOTE_ADDR'])
        trusted_proxies: '127.0.0.1,REMOTE_ADDR'

Ось і все! Критично важливо, щоб ви запобігли трафіку з усіх недовірених джерел. Якщо ви доозволите сторонній трафік, він може "підробити" справжні IP-адреси та іншу інформацію.

Якщо ви також використовуєте зворотний проксі над вашим балансувальником навантаження (наприклад, CloudFront), виклику $request->server->get('REMOTE_ADDR') буде недостатньо, так як він буде довіряти лише вузллу, що знаходиться прямо над вашим додатком (в даному випадку - вашому балансувальнику наванатаження). Вам також потрібно додати IP-адреси або діапазон будь-якого додаткового проксі (наприклад, IP-діапазони CloudFront) до масиву довірених проксі.

Зворотний проксі у підшляху / підкаталозі

Якщо ваш додаток Symfony працює через зворотний проксі, і він обслуговується у підшляху/підкаталозі, Symfony може генерувати некоректні URL-адреси, які ігнорують підшлях/підкаталог зворотного проксі.

Щоб виправити це, вам потрібно передати Symfony префікс зворотного проксі підшляху/підкаталогy, встановивши заголовок X-Forwarded-Prefix. Цей заголовок зазвичай можна налаштувати у конфігурації вашого зворотного проксі. Сконфігуруйте X-Forwarded-Prefix як довірений заголовок, щоб мати змогу використовувати цю функцію.

Префікс X-Forwarded-Prefix використовується Symfony для додавання префікса до базової URL-адреси обʼєктів запиту, яка використовується для генерації абсолютних шляхів та URL в додатках Symfony. Без цього заголовка базовий URL буде визначатися лише на основі конфігурації веб-сервера, на якому запущено Symfony, що призводить до некоректних шляхів/URL, коли додаток обслуговується за підшляхом/підкаталогом через зворотний проксі.

Наприклад, якщо ваш додаток Symfony обслуговується безпосередньо за URL на кшталт https://symfony.tld/ і ви хочете використовувати зворотній проксі для обслуговування додатку за адресою https://public.tld/app/, вам потрібно встановити заголовок X-Forwarded-Prefix як /app/ у вашій конфігурації зворотного проксі. Без цього заголовка Symfony генеруватиме URL на основі базової URL-адреси сервера (наприклад, /my/route) замість правильного /app/my/route, який необхідний для доступу до маршруту через зворотний проксі.

Заголовок може бути різним для кожного зворотного проксі, щоб доступ через різні зворотні проксі, які обслуговуються в різних підшляхах/підкаталогах, міг оброблятися коректно.

Користувацькі заголовки при використанні зворотного проксі

Деякі зворотні проксі (на кшталт CloudFront з CloudFront-Forwarded-Proto) можуть змушувати вас використовувати користувацький заголовок. Наприклад, у вас є Custom-Forwarded-Proto замість X-Forwarded-Proto.

В такому випадку вам знадобиться встановити заголовок X-Forwarded-Proto зі значенням Custom-Forwarded-Proto достатньо рано у вашому додатку, тобто, перед обробкою запиту:

1
2
3
4
5
6
// public/index.php

// ...
$_SERVER['HTTP_X_FORWARDED_PROTO'] = $_SERVER['HTTP_CUSTOM_FORWARDED_PROTO'];
// ...
$response = $kernel->handle($request);

Перевизначення конфігурації за прихованим завершенням SSL

Деякі хмарні налаштування (наприклад, запуск контейнера Docker за допомогою "Web App for Containers" в Microsoft Azure) виконують завершення SSL-з'єднання і зв'язуються з вашим веб-сервером по HTTP, але не змінюють віддалену адресу і не встановлюють заголовки X-Forwarded-*. Це означає, що функція довіреного проксі в Symfony не може вам допомогти.

Після того, як ви переконалися, що ваш сервер доступний лише через хмарний проксі по HTTPS а не через HTTP, ви можете перевизначити інформацію, яку ваш веб-сервер надсилає PHP. Для Nginx це може виглядати так:

1
2
3
4
5
6
7
location ~ ^/index\.php$ {
    fastcgi_pass 127.0.0.1:9000;
    include fastcgi.conf;
    # Збрехати Symfony про протокол і порт, щоб вона згенерувала правильні HTTPS URL
    fastcgi_param SERVER_PORT "443";
    fastcgi_param HTTPS "on";
}