-
-
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
reverseproxy: Sanitize scheme and host on incoming requests #4237
Conversation
581a03b
to
98762fb
Compare
As discussed in Slack, going to push this back to the 2.5 tree because we're not sure yet what the side-effects could be. We want more time to investigate, and I'd be more comfortable pushing a riskier fix into a minor release than a patch release. |
What if we just did this sanitization in the reverse proxy code instead of globally for the whole HTTP server? Just thinking of something safer and less scary first. |
We could, but that would be no different because we don't use a copy of Did you get a chance to reach out to any Go people to see if they agree this makes sense? |
The difference is that the modification would only happen for the purposes of proxying to the upstream. After the proxy has handled the request, no other handlers will be handling it, so I'm not too worried about the mutated Request. If that is a problem, those values are very easy to restore (unlike headers, which we do kind of "snapshot" anyway). We do that here: caddy/modules/caddyhttp/reverseproxy/reverseproxy.go Lines 391 to 401 in c48fadc
Granted, this is racey, and we could probably find a better way to handle this, but I'm just saying that making a more localized change is less scary and might be just as effective. |
98762fb
to
07de5b1
Compare
63161ba
to
233070c
Compare
dac6e7c
to
233070c
Compare
@mholt I updated the PR to move this logic to the I'm not a fan of all this code being right in ServeHTTP, but it kinda needs to be in there because of the Maybe you have ideas on how to refactor this? |
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.
This is much less scary, thanks. I think this way of doing it is fine for now, maybe we can refactor later if we feel it would be beneficial.
My only request is minor, otherwise this is an approve. Good job.
dc03e31
to
5b810fc
Compare
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.
Thank you 😃
See https://caddy.community/t/caddy-attempts-to-connect-downstream-server-via-https-although-not-configured-to-do-so/12765 for context, and later another report of the same problem in https://caddy.community/t/reverse-proxying-trying-to-make-a-tls-connection-to-an-http-only-backend/13954
Basically some wacky HTTP clients may sometimes make HTTP requests with request-line like this:
Most well behaved clients make requests like this:
Technically, both are valid as per HTTP RFCs, but the former ends up breaking some assumptions that the code makes, like that the scheme is empty before being passed onto the
reverse_proxy
module.The effect was that these requests would tell
http.Client
to use a different scheme than configured. For example, configuredreverse_proxy
to proxy over HTTP, but the scheme in the original request's request-line hadhttps://
so it would try to proxy over HTTPS 😱The docs for
Request.URL
do say:So it's definitely pretty unexpected to receive the scheme and host in the URL.
This change should just wipe out the scheme and host in the URL, which are otherwise covered by
Request.Host
andRequest.TLS
(and that's how all of the code in Caddy access the host and whether the request was secured).I realize this is a risky change because it affects every request handled by Caddy. We should definitely tread lightly here. But I think this is the most logical and simplest way to solve this.I've adjusted the implementation to only do the sanitization in thereverseproxy
package, and to restore it afterreverseproxy
is done.