-
-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Add WebUI reverse proxy source IP resolution #15047
Conversation
a325aa2
to
d2dcc47
Compare
@HiFiPhile |
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.
A few things not mentioned in coding guidelines
68cf37c
to
3a1ccf4
Compare
src/webui/webapplication.cpp
Outdated
{ | ||
if (clientAddress.setAddress(remoteIp) && clientAddress.isGlobal()) | ||
{ | ||
hasGlobalIp = true; |
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.
You can return clientAddress;
here.
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.
So what about changing it?
PS I hope that your disagreements with @qix67 do not mean that this PR is not ready?
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.
So what about changing it?
I've changed it in the last commit.
PS I hope that your disagreements with @qix67 do not mean that this PR is not ready?
No we only have some differences in proxy configuration, this PR can fit both cases.
src/webui/webapplication.cpp
Outdated
|
||
if (!forwardedFor.isEmpty()) | ||
{ | ||
// client address is the 1st global IP in X-Forwarded-For or, if none available, the 1st IP in the list |
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.
IIRC, client address is always first. Any subsequent addresses become to midway proxies. Am I wrong?
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.
Yes, you are wrong but it is a fairly common error.
When I access to qbittorrent from my work, I have the following the X-forwarded-for
172.29.225.237,194.254.4.90,10.0.3.254,127.0.0.1
- First IP is the local IP of my desktop PC at work.
- 2nd IP is the public IP used by my work proxy.
- 3rd IP is the local IP of my reverse proxy at home. This reverse proxy runs on my gateway and performs SSL termination.
- 4th IP is added by nginx running on the same computer as qbittorrent (proxy_pass).
The correct IP is always the last public IP, here, the 2nd IP.
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.
Yes, you are wrong but it is a fairly common error.
I was only guided by https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#syntax
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.
It is correct, the first IP is the real client IP but it does not mean it is a public IP, that's why it is kinda misleading.
The worst case I ever seen is something like that (combination of proxy, VPN and reverse proxies):
192.168.0.1, public_IP, 10.0.23.1, public_IP2, 172.29.226.1, 127.0.0.1
In this case, the correct public IP is public_IP2 (last public IP). I admit, it is a very unusual settings but it is a valid value.
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.
OK, thanks.
One more question.
We specify the address of the proxy server to make sure that the request (containing X-Forwarded-For
header) is received from it. This assumes that requests can come from both the proxy server address and another address. Is it a valid usecase to have a configured proxy server and at the same time some other access channels for untrusted clients?
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.
I think for a safe reverse proxy configuration, it's better to delete X-Forwarded-For
at frontend, so someone from the
outside cannot spoof this header. It also ensures the first IP in the header is the client IP.
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.
I think for a safe reverse proxy configuration, it's better to delete X-Forwarded-For at frontend, so someone from the
outside cannot spoof this header. It also ensures the first IP in the header is the client IP.
I don't think it will change anything as the frontend will always add the incoming IP address at the end of X-Forwarded-For string. Anything existing before should be assumed unsafe and purely informational. That's why taking the last public IP is important.
Moreover, it is not always possible to reconfigure the reverse proxy.
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.
We specify the address of the proxy server to make sure that the request (containing
X-Forwarded-For
header) is received from it. This assumes that requests can come from both the proxy server address and another address. Is it a valid usecase to have a configured proxy server and at the same time some other access channels for untrusted clients?
The point is that if it is only available through a proxy (as it should be, IMO; i.e., if we have a proxy, then it should only be available through it), then we do not need to have a proxy address check, but just specify whether it should resolve the client address or not.
It looks like we should still allow user to explicitly set the proxy address for better security. But maybe we can be more lenient in another case, i.e. allow the user to enable client address resolution without explicitly specifying the proxy address?
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.
But maybe we can be more lenient in another case, i.e. allow the user to enable client address resolution without explicitly specifying the proxy address?
It's hard to say, people do it differently.
For example Gitea allows client address resolution from 127.0.0.0 by default, SFTPGo needs to specify proxy address whitelist.
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.
It's just that we could provide more options to the user by placing more responsibility on them (of course, by warning them about this). If he is confident in the security of his network environment settings, then allow him not to explicitly specify the proxy server address.
In any case, this is not a blocking comment. So if you don't agree, you can continue as is and wait for user feedback.
src/base/preferences.cpp
Outdated
@@ -761,6 +761,26 @@ void Preferences::setWebUICustomHTTPHeaders(const QString &headers) | |||
setValue("Preferences/WebUI/CustomHTTPHeaders", headers); | |||
} | |||
|
|||
bool Preferences::isWebUIReverseProxyEnabled() const | |||
{ | |||
return value("Preferences/WebUI/ReverseProxyEnabled", false).toBool(); |
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.
IMO, "reverse proxy enabled" confuses. One may think that there is some built-in "reverse proxy" feature.
Maybe "forwarded client IP enabled/used/allowed"?
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.
Maybe "Reverse proxy support" ? I think the word "reverse proxy" makes the purpose clear.
src/base/preferences.cpp
Outdated
|
||
QString Preferences::getWebUIReverseProxyAddress() const | ||
{ | ||
return value("Preferences/WebUI/ReverseProxyAddress", "").toString().trimmed(); |
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.
Can't it be used with some kind of "forward" proxy as well? I would avoid explicitly specifying "reverse" term.
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.
I think a list of "trusted_proxies" is not a bad idea.
My input: The idea of a "Trusted proxies list" is good in case people have multiple proxies The warning for configuring is also in the right place since misconfiguration can lead to IP impersonation 1 thing i would propose as a tiny bonus is being able to manually enter the header name that is checked for IP. Personally i have been using "X-Forwarded-For" but there is a chance some other people might be unhappy. Anyways this pull request is already a banger i can recommend |
Co-authored-by: qix67 Co-authored-by: HiFiPhile <admin@hifiphile.com>
Co-authored-by: Vladimir Golovnev <glassez@yandex.ru>
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.
Only one last comment, I'm fine with the rest.
Thank you! |
@HiFiPhile |
Yes in general I maintain my commits. |
Co-authored-by: qix67 Co-authored-by: HiFiPhile <admin@hifiphile.com>
This PR is a revive of #9176 .
Since the orignal author @qix67 is no longer maintaining the PR and based on the discussion some collaborators are also in favor of this feature, I rebased the PR to latest master.
It also includes some refactor and renaming.
Co-authored-by: qix67
Co-authored-by: HiFiPhile admin@hifiphile.com