-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve X-Forwarded-* request headers handling #38696
Conversation
Hey there @home-assistant/core, mind taking a look at this pull request as its been labeled with an integration ( |
Co-authored-by: Martin Hjelmare <[email protected]>
Co-authored-by: Martin Hjelmare <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 small comments, but other looks fine 👍 good work
Co-authored-by: Franck Nijhof <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good (discussed out of band)
Co-authored-by: Paulus Schoutsen <[email protected]> Co-authored-by: Martin Hjelmare <[email protected]> Co-authored-by: Franck Nijhof <[email protected]> Co-authored-by: Pascal Vizeli <[email protected]>
Co-authored-by: Paulus Schoutsen <[email protected]> Co-authored-by: Martin Hjelmare <[email protected]> Co-authored-by: Franck Nijhof <[email protected]> Co-authored-by: Pascal Vizeli <[email protected]>
i think i may be missing part of the config here. Caching is handled by cloudflare on my side. i tried adding their proxy ips however still getting Too many headers for X-Forwarded-For |
@errolsancaktar if you have an issue, please create an issue. Thanks! |
Hi @frenck . Sorry to bother you.
I was wondering what was the reasoning behind this. According to specs, the first IP is definitely the originator. Why replacing/loosing this information by replacing it by an intermediate proxy? That also has the inconvenience that "trusted_proxy" has 2 different meanings:
There are a couple of threads on the forum where users are using cloudflare proxies upstream (don't ask me why/how), and, unless they put in their config the full list of possible cloudflare proxies, they end up with "Login attempt or request with invalid authentication" with a cloudflare address, which is quite confusing. |
That is incorrect. Nevertheless, this is an PR from August 2020, many things have changed in between. If you want to report a bug, please raise an issue. This PR has been closed and handled a long time ago. Thanks 👍 |
Breaking change
The processing of data received from reverse proxies is now more strictly handled. Invalid or malformed
X-Forwarded-For
headers will now result in an HTTP 400 error (Bad Request). Support forX-Forwarded-Proto
andX-Forwarded-Host
has been added.Additionally, Home Assistant will now log cases of a reverse proxy being used, but not configured with Home Assistant. Make sure, you set the
use_x_forwarded_for
andtrusted_proxies
in your Home Assistanthttp
configuration correctly to avoid warnings.Proposed change
Improves the handling of
X-Forwarded-*
headers, replacing thereal_ip
middleware with aforwarded
middleware.request[KEY_REAL_IP]
"hack".x_forwarded_for
is enabled in thehttp
configuration andtrusted_proxies
are set.X-Forwarded-For
(see processing info below)X-Forwarded-Proto
X-Forwarded-Host
The processing is more strict and will throw an HTTP 400 error in case something is wrong. This might be a breaking change, before this PR, Home Assistant would accept about anything.
How headers are processed
To add clarification to the PR, this PR processes the headers in the following way:
X-Forwarded-For: <client>, <proxy1>, <proxy2>
e.g.,
X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178
We go through the list from the right side, and skip all entries that are in our trusted proxies list. The first non-trusted IP is used as the client IP. If all items in the
X-Forwarded-For
are trusted, including the most left item (<client>
), the most left item is used. In the latter case, the client connection originated from an IP that is also listed as a trusted proxy IP or network.X-Forwarded-Proto: <client>, <proxy1>, <proxy2>
e.g.,
X-Forwarded-Proto: https, http, http
OR
X-Forwarded-Proto: https
(one entry, even with multiple proxies)The
X-Forwarded-Proto
is determined based on the corresponding entry of theX-Forwarded-For
header that is used/chosen as the client IP. However, some proxies, for example, Kubernetes NGINX ingress, only retain one element in theX-Forwarded-Proto
header. In that case, we'll just use what we have.X-Forwarded-Host: <host>
e.g.,
X-Forwarded-Host: example.com
If the previous headers are processed successfully, and the
X-Forwarded-Host
is present, it will be used.Additionally:
X-Forwarded-For
header is found, the processing of all headers is skipped.X-Forwarded-For
,X-Forwarded-Proto
orX-Forwarded-Host
are found, an HTTP 400 status code is thrown.X-Forwarded-For
header is found, an HTTP 400 status code is thrown.Alternatives/Additions to consider
X-Forwarded-For
chain to be valid.Right now we stop processing at the first untrusted IP, however, we can improve security a bit, by requiring the whole chain to be valid (excluding
<client>
as that one is expected to be untrusted). This might add configuration complexity for the end-user.We now go through the list of IP addresses in
X-Forwarded-For
and accept any amount of values/hops. Ideally, we can improve security a bit by requiring specification on the number of hops expected. This can be problematic when Home Assistant is deployed in a more advanced and dynamic environment where this isn't known. This also adds configuration complexity for the end-user.Right now, we don't look at the order of reverse proxies in the
X-Forwarded-For
. We could use thetrusted_proxies
list as the order and number of proxies expected which greatly improves expected results, however, this is a larger breaking change and can be problematic when Home Assistant is deployed in a more advanced and dynamic environment where this isn't known. The level of breaking change is most like to cause quite a lot of configuration confusing with the end-user.X-Forwarded-Port
.X-Real-Ip
.This could be done if the client connected to the socket is trusted and no
X-Forwarded-For
is set.Forwarded
headers.While
X-Forwarded-For
is the defacto standard, however,Forwarded
is standardized in RFC7239. It provides more features as well and is easier to process. IfForwarded
is present,X-Forwarded-*
could be ignored.References
aiohttp
: https://github.com/aio-libs/aiohttp-remotes/blob/master/aiohttp_remotes/x_forwarded.pyTodo
forwarded
middlewarerequest[HA_REAL_IP]
tests/components/emulated_hue/test_hue_api.py::test_external_ip_blocked
, external IP needs to be patched differently.Manual regression tests
Type of change
Example entry for
configuration.yaml
:Additional information
Checklist
black --fast homeassistant tests
)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest
.requirements_all.txt
.Updated by running
python3 -m script.gen_requirements_all
..coveragerc
.The integration reached or maintains the following Integration Quality Scale: