From bb616bed945f7cfa197bf1e7821819764435026b Mon Sep 17 00:00:00 2001 From: Magnus Nordlander Date: Mon, 2 May 2016 14:31:58 +0200 Subject: [PATCH 1/3] Documented how to configure Symfony correctlywhen your reverse proxy is not handling the Forwarded header the way Symfony expects it to. --- .../http_foundation/trusting_proxies.rst | 21 ++++++++++----- cookbook/cache/varnish.rst | 15 +++++++++++ .../request/load_balancer_reverse_proxy.rst | 26 ++++++++++++++++++- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/components/http_foundation/trusting_proxies.rst b/components/http_foundation/trusting_proxies.rst index fbe9b30cdee..0d65854aa2d 100644 --- a/components/http_foundation/trusting_proxies.rst +++ b/components/http_foundation/trusting_proxies.rst @@ -11,9 +11,9 @@ Trusting Proxies If you find yourself behind some sort of proxy - like a load balancer - then certain header information may be sent to you using special ``X-Forwarded-*`` -headers. For example, the ``Host`` HTTP header is usually used to return -the requested host. But when you're behind a proxy, the true host may be -stored in a ``X-Forwarded-Host`` header. +headers or the ``Forwarded`` header. For example, the ``Host`` HTTP header is +usually used to return the requested host. But when you're behind a proxy, +the true host may be stored in a ``X-Forwarded-Host`` header. Since HTTP headers can be spoofed, Symfony does *not* trust these proxy headers by default. If you are behind a proxy, you should manually whitelist @@ -30,11 +30,19 @@ your proxy. // only trust proxy headers coming from this IP addresses Request::setTrustedProxies(array('192.0.0.1', '10.0.0.0/8')); +You should also make sure that your proxy filters unauthorized use of these +headers, e.g. if a proxy natively uses the ``X-Forwarded-For`` header, it +should not allow clients to send ``Forwarded`` headers to Symfony. + +If your proxy does not filter headers appropriately, you need to configure +Symfony not to trust the headers your proxy does not filter (see below). + Configuring Header Names ------------------------ By default, the following proxy headers are trusted: +* ``Forwarded`` Used in :method:`Symfony\\Component\\HttpFoundation\\Request::getClientIp`; * ``X-Forwarded-For`` Used in :method:`Symfony\\Component\\HttpFoundation\\Request::getClientIp`; * ``X-Forwarded-Host`` Used in :method:`Symfony\\Component\\HttpFoundation\\Request::getHost`; * ``X-Forwarded-Port`` Used in :method:`Symfony\\Component\\HttpFoundation\\Request::getPort`; @@ -43,6 +51,7 @@ By default, the following proxy headers are trusted: If your reverse proxy uses a different header name for any of these, you can configure that header name via :method:`Symfony\\Component\\HttpFoundation\\Request::setTrustedHeaderName`:: + Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'X-Forwarded'); Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X-Proxy-For'); Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X-Proxy-Host'); Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X-Proxy-Port'); @@ -51,9 +60,9 @@ can configure that header name via :method:`Symfony\\Component\\HttpFoundation\\ Not Trusting certain Headers ---------------------------- -By default, if you whitelist your proxy's IP address, then all four headers +By default, if you whitelist your proxy's IP address, then all five headers listed above are trusted. If you need to trust some of these headers but not others, you can do that as well:: - // disables trusting the ``X-Forwarded-Proto`` header, the default header is used - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, ''); + // disables trusting the ``Forwarded`` header + Request::setTrustedHeaderName(Request::HEADER_FORWARDED, ''); diff --git a/cookbook/cache/varnish.rst b/cookbook/cache/varnish.rst index e5bfcce1c95..a4d9c2cb9de 100644 --- a/cookbook/cache/varnish.rst +++ b/cookbook/cache/varnish.rst @@ -24,6 +24,21 @@ Remember to configure :ref:`framework.trusted_proxies ` headers are used. +Varnish, in its' default configuration, sends the ``X-Forwarded-For`` header but +does not filter out the ``Forwarded``. If you have access to the Varnish +configuration file, you can configure Varnish to remove the ``Forwarded`` +header:: + +.. code-block:: varnish4 + + sub vcl_recv { + remove req.http.Forwarded; + } + +If you do not have access to your Varnish configuration, you can instead +configure Symfony to distrust the ``Forwarded`` header as detailed in +:doc:`/cookbook/request/load_balancer_reverse_proxy`. + .. _varnish-x-forwarded-headers: Routing and X-FORWARDED Headers diff --git a/cookbook/request/load_balancer_reverse_proxy.rst b/cookbook/request/load_balancer_reverse_proxy.rst index 343c9c35fa8..2b93fc8ee68 100644 --- a/cookbook/request/load_balancer_reverse_proxy.rst +++ b/cookbook/request/load_balancer_reverse_proxy.rst @@ -23,7 +23,7 @@ via HTTPS, the client's port and the hostname being requested. Solution: trusted_proxies ------------------------- -This is no problem, but you *do* need to tell Symfony that this is happening +This is no problem, but you *do* need to tell Symfony what is happening and which reverse proxy IP addresses will be doing this type of thing: .. configuration-block:: @@ -62,6 +62,9 @@ the IP address ``192.0.0.1`` or matches the range of IP addresses that use the CIDR notation ``10.0.0.0/8``. For more details, see the :ref:`framework.trusted_proxies ` option. +You are also saying that you trust that the proxy does not send conflicting +headers, e.g. sending both X-Forwarded-For and Forwarded in the same request. + That's it! Symfony will now look for the correct headers to get information like the client's IP address, host, port and whether the request is using HTTPS. @@ -95,6 +98,27 @@ That's it! It's critical that you prevent traffic from all non-trusted sources. If you allow outside traffic, they could "spoof" their true IP address and other information. +My Reverse Proxy sends X-Forwarded-For but does not filter the Forwarded header +------------------------------------------------------------------------------- + +Many popular proxy implementations do not yet support the Forwarded header and +does not filter it by default configuration. Ideally, you would configure this +in your proxy, but if this is not possible, you can tell Symfony to distrust +the Forwarded header, while still trusting your proxy's X-Forwarded-For header. + +This is done inside of your front controller:: + + // web/app.php + + // ... + Request::setTrustedHeaderName(Request::HEADER_FORWARDED, null); + + $response = $kernel->handle($request); + // ... + +Configuring the proxy server trust is very important, as not doing so will +malicious users to "spoof" their IP address. + My Reverse Proxy Uses Non-Standard (not X-Forwarded) Headers ------------------------------------------------------------ From 992e3dd17e0e962f2f578aee416a4132d6ee22de Mon Sep 17 00:00:00 2001 From: Magnus Nordlander Date: Mon, 2 May 2016 15:08:22 +0200 Subject: [PATCH 2/3] Updated to remove grammar errors --- cookbook/cache/varnish.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/cache/varnish.rst b/cookbook/cache/varnish.rst index a4d9c2cb9de..93c68f3640c 100644 --- a/cookbook/cache/varnish.rst +++ b/cookbook/cache/varnish.rst @@ -24,8 +24,8 @@ Remember to configure :ref:`framework.trusted_proxies ` headers are used. -Varnish, in its' default configuration, sends the ``X-Forwarded-For`` header but -does not filter out the ``Forwarded``. If you have access to the Varnish +Varnish, in its default configuration, sends the ``X-Forwarded-For`` header but +does not filter out the ``Forwarded`` header. If you have access to the Varnish configuration file, you can configure Varnish to remove the ``Forwarded`` header:: From f2903524b51edf6516ff7ce0a746129881ad8a87 Mon Sep 17 00:00:00 2001 From: Magnus Nordlander Date: Fri, 6 May 2016 01:12:36 +0200 Subject: [PATCH 3/3] Updates according to review comments. --- components/http_foundation/trusting_proxies.rst | 4 ++-- cookbook/cache/varnish.rst | 4 ++-- cookbook/request/load_balancer_reverse_proxy.rst | 8 +++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/components/http_foundation/trusting_proxies.rst b/components/http_foundation/trusting_proxies.rst index 0d65854aa2d..2783f5ed521 100644 --- a/components/http_foundation/trusting_proxies.rst +++ b/components/http_foundation/trusting_proxies.rst @@ -13,7 +13,7 @@ If you find yourself behind some sort of proxy - like a load balancer - then certain header information may be sent to you using special ``X-Forwarded-*`` headers or the ``Forwarded`` header. For example, the ``Host`` HTTP header is usually used to return the requested host. But when you're behind a proxy, -the true host may be stored in a ``X-Forwarded-Host`` header. +the actual host may be stored in a ``X-Forwarded-Host`` header. Since HTTP headers can be spoofed, Symfony does *not* trust these proxy headers by default. If you are behind a proxy, you should manually whitelist @@ -65,4 +65,4 @@ listed above are trusted. If you need to trust some of these headers but not others, you can do that as well:: // disables trusting the ``Forwarded`` header - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, ''); + Request::setTrustedHeaderName(Request::HEADER_FORWARDED, null); diff --git a/cookbook/cache/varnish.rst b/cookbook/cache/varnish.rst index 93c68f3640c..31094a95d7a 100644 --- a/cookbook/cache/varnish.rst +++ b/cookbook/cache/varnish.rst @@ -27,7 +27,7 @@ in the Symfony configuration so that Varnish is seen as a trusted proxy and the Varnish, in its default configuration, sends the ``X-Forwarded-For`` header but does not filter out the ``Forwarded`` header. If you have access to the Varnish configuration file, you can configure Varnish to remove the ``Forwarded`` -header:: +header: .. code-block:: varnish4 @@ -37,7 +37,7 @@ header:: If you do not have access to your Varnish configuration, you can instead configure Symfony to distrust the ``Forwarded`` header as detailed in -:doc:`/cookbook/request/load_balancer_reverse_proxy`. +:ref:`the cookbook `. .. _varnish-x-forwarded-headers: diff --git a/cookbook/request/load_balancer_reverse_proxy.rst b/cookbook/request/load_balancer_reverse_proxy.rst index 2b93fc8ee68..c247d661152 100644 --- a/cookbook/request/load_balancer_reverse_proxy.rst +++ b/cookbook/request/load_balancer_reverse_proxy.rst @@ -98,12 +98,14 @@ That's it! It's critical that you prevent traffic from all non-trusted sources. If you allow outside traffic, they could "spoof" their true IP address and other information. -My Reverse Proxy sends X-Forwarded-For but does not filter the Forwarded header +.. _cookbook-request-untrust-header: + +My Reverse Proxy Sends X-Forwarded-For but does not Filter the Forwarded Header ------------------------------------------------------------------------------- Many popular proxy implementations do not yet support the Forwarded header and -does not filter it by default configuration. Ideally, you would configure this -in your proxy, but if this is not possible, you can tell Symfony to distrust +do not filter it by default. Ideally, you would configure this +in your proxy. If this is not possible, you can tell Symfony to distrust the Forwarded header, while still trusting your proxy's X-Forwarded-For header. This is done inside of your front controller::