Как сконфигурировать Symfony, чтобы она работала за распределителем нагрузки или обратным прокси

Дата обновления перевода 2022-01-03

Как сконфигурировать Symfony, чтобы она работала за распределителем нагрузки или обратным прокси

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

В большинстве случаев это не вызывает проблем с Symfony. Но, когда запрос проходит через прокси, отправляется определённая информация запроса, используя либо стандартный заголовок Forwarded, либо заголовки X-Forwarded-*. Например, вместо прочтения заголовка REMOTE_ADDR (который теперь будет IP адресом вашего обратного прокси), настоящий IP пользователя будет храниться в стандартном заголовке Forwarded: for="..." или заголовке X-Forwarded-For.

Если вы не сконфигурируете Symfony так, чтобы она искала такие заголовки, то вы будете получать неправильную информауию об IP адресе клиента, независимо от того, подключается он через HTTPS или нет, клиентского порта и запрашиваемого имени хоста.

Решение: setTrustedProxies()

Чтобы исправить это, вам нужно сказать Symfony, каким IP адресам обратного прокси можно доверять, и какие заголовки использует ващ прокси для отправки информации:

  • YAML
  • XML
  • PHP
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']

5.2

В предыдущих версиях Symfony, пример выше использовал HEADER_X_FORWARDED_ALL, чтобы доверять всем заголовкам "X-Forwarded-", но эта константа устарела начиная с 5.2 в пользу индивидуальных констант HEADER_X_FORWARDED_*.

Caution

Включение опции Request::HEADER_X_FORWARDED_HOST делает приложение уязвимым к атакам заголовков хостинга HTTP. Make sure the proxy really sends an x-forwarded-host header.

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

5.2

Функция конфигурации доверенных прокси и заголовков с опциями trusted_proxies и trusted_headers была представлена в Symfony 5.2. В более ранних версиях Symfony вам нужно было использовать метод Request::setTrustedProxies() в файле public/index.php.

Caution

Функция "доверенные прокси" не работает, как ожидается, при использовании модуля 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 адреса и другую информацию.

Tip

В приложениях, использующих Symfony Flex , вы можете установить переменную окружения TRUSTED_PROXIES:

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

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

Пользовательские заголовки при использовании обратного прокси

Некоторые обратные прокси (вроде 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);