Как сконфигурировать Symfony, чтобы она работала за распределителем нагрузки или обратным прокси
Дата обновления перевода 2024-07-19
Как сконфигурировать 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 10 11
# config/packages/framework.yaml
framework:
# ...
# IP-адрес (или диапазон) вашего прокси
trusted_proxies: '192.0.0.1,10.0.0.0/8'
# сокращение для диапазона приватных IP-адресов вашего прокси
trusted_proxies: 'private_ranges'
# доверять *всем* заголовкам "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. Make sure the proxy really
sends an x-forwarded-host
header.
Объект Запрос имеет несколько констант 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 примечания. В этомслучае, вам нужно будет - очень осторожно - доверить всем прокси.
- Сконфигурируйте ваш(и) веб-сервер(ы), чтобы они не отвечали на траффик любых клиентов, кроме ваших распределителей нагрузки. Для AWS это можно сделать с помощью групп безопасности.
Когда вы гарантировали, что траффик будет исходить только от доверенных обратных прокси, сконфигурируйте 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, установив заголовок X-Forwarded-Prefix
. Этот заголовок
обычно настраивается в конфигурации вашего обратного прокси. Сконфигурируйте
X-Forwarded-Prefix
как доверенный заголовок, чтобы иметь возможность использовать
эту функцию.
Префикс X-Forwarded-Prefix
используется Symfony для добавления префикса к базовому
URL-адресу объектов запроса, который используется для генерирования абсолютных путей и
URL-адресов. Без этого заголовка базовый 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;
# Lie to Symfony about the protocol and port so that it generates the correct HTTPS URLs
fastcgi_param SERVER_PORT "443";
fastcgi_param HTTPS "on";
}