-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Support HTTPS environment variable via x-forwarded-proto header #369
base: master
Are you sure you want to change the base?
Conversation
Looks like there's an issue with test 338.6, it fails with:
|
Hmm, I'm a bit on the fence with this one -- on the one hand, it'd make PHP applications transparently able to detect this sort of thing, but on the other hand, it'd be a further divergence between the Apache and FPM variants and it should be fairly trivial to add this to a local I think the "correct" solution would be for PHP applications to also check Are there any official recommendations regarding this sort of thing from PHP upstream? |
.htaccess would require exposed docroot and many apps, like drupal, already have stuff in .htaccess that they need so overwriting it with a custom one introduces maintenance challenges. You are correct that it is more of an application issue but given how long this issue has persisted, checking both $_SERVER['HTTPS'] for locally terminated SSL and $_SERVER['HTTP_X_FORWARDED_PROTO'] for remotely terminated SSL every time full URL needs to be generated, a secure cookie flag set etc, is indeed not too likely to catch on. :) There is dmikusa/cf-php-apache-buildpack#6 about this same thing and they submitted https://bugs.php.net/bug.php?id=66398 that through documentation would've suggested developers to handle the header consistently but the issue is still open after 3y. For the time being my concern is that most people after they do |
I'm not really familiar with FPM, but as I understand fastcgi is a binary protocol that browsers don't speak so it requires an httpd to act as a middleman. In a setup where webapp is served by php:fpm container, is it typically accessed via a proxy to the container's port 9000? It seems that at least with mod_proxy_fcgi requests also inherit environment variables from httpd, at least I could pass HTTPS flag from apache to the dockerized php like this:
If I understood correctly then no changes to the docker container configuration is required to support HTTPS envvar with FPM? Though it would be nice to provide documentation in docker hub readme preferably, so that people know to set that envvar in FPM's case, or otherwise pass a X-Forwarded-Proto header, unless they are using 3rd party SSL termination that already provides it (AWS ELB for example). |
Sorry for the long delay. I think http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy is a good example from a relatively large and popular PHP application, whose documentation suggests that manually checking the value of I'm going to close, but I think this discussion will serve as a good reference point for future travelers! Thanks! ❤️ |
Please reopen this one.
|
I wouldn't trust Wordpress on this. The code snippet they suggest right now is incorrect, as it trusts values that may come from the client. In the end, the snippet fakes
As said in #943, I don't think PHP should ever add this kind of logic. Also, I'm pretty sure most of the users would prefer a patched behaviour. If you're an advanced user who needs the original variables, mentioning
I have yet to see an example of this...
I don't think that's an excuse, they could have put it behind a config option like Drupal 😞
Not really, FPM does not include a webserver... Configuring a webserver is their task, and if they want the same behaviour as |
Not sure why I comment on this, but heh. :) Don't trust I agree it's a lot better to set this here (by the admin), than if braindead application does check XPP itself, but enabling it by default may be fatal on the unsuspecting admin. Because even if their app is secure by default and only trusts See, if there is no reverse proxy (or it doesn't disallow port 80), I only have to send Let's assume this completely made up scenario for a second: An application is accessible via both Port 80, and through TLS on 443 as
So it allows logins only over HTTPS (if server env So how is this bad? All they achieved is getting a broken page and possibly some https-only cookies, right? Don't bother with the rest here, it got trashed. ;) Well, yes, unless $badguy is really keen on getting your site login. Then they could for example register the domain mys1te.com, even grab a valid lets-encrypt certificate for it, and run their own reverse-proxy that serves mysite.com:80 with Then they add a little regex that defaces the front-page when loaded, and send you this email: "Dear $siteadmin, I just noticed your website on So of course you click the link, and indeed, that is your site, with the valid LE cert, and the page is broken! All flustered, you log in to /admin.php to check what's going on and .... yeah, your insecure login just got phished. But that's just wordpress, and a dumb example, so who cares. Again, I agree it makes sense to have the option here, if the user is made aware of it and has the choice to disable or enable it. |
That is correct in theory, but not in practice (see first point below)
This attack only works if there's no proxy (or a misconfigured proxy that doesn't send the header). But then, the app will not work correctly because it will perceive all requests as http. This will force the user to setup the proxy (which makes this attack impossible, since the client no longer controls the header). Second: This requires the attacker to have the capability to add arbitrary headers to the request. If the attacker has this privilege, why wouldn't they be able to send an https request in the first place? Third: why would the server need to validate the protocol for security purposes? protocol validation is meaningful to the client (which needs to authenticate itself to the server) Given all this, it's really hard for me to come up with an example where this would open a vulnerability; even the official snippet from Wordpress allows the client to forge So in the end, I think it would be okay to enable this by default & add a warning to the documentation explaining what it does, and how to disable it.
This doesn't make sense 😞 The attacker could just serve mysite.com:443, it would work the same... |
Best things first ;)
Hahaha, dang, girl! Dismantled that completely there! ;) You are quite correct, on reflection I can just re-wrap the TLS connection for the same results.
Yes, exactly so. Or possibly, if it doesn't strip the header from a client.
This I do not get. Do you talk about a CGI environment here, as opposed to http requests? Or a PROXY protocol connection to Apache?
I'll say. It seems I have trouble myself ;) Given this one is a boolean setting, it's relatively safe from direct exploiting. But imagine, if you will, an application that interprets some X_SSL_* headers from a TLS proxy about the client connection, only when it believes to be safe behind such a proxy; then an attacker And if you won't, I'll rest my case. But I'll stand by my point that elevating insecure input to a usually trusted environment is not a good idea, even if it looks safe enough at a glance.
And it doesn't seem to be a default enabled setting there either, though they at least know their application and how that setting will affect it. Here on the other hand, we're packaging only an interpreter (environment), knowing neither what applications will run in it, nor in which environment the container will be run. Then making predictions on both counts might not be the best idea.
I might just have to vote for you there, seeing how you took down my argument. But no, I'll leave that up to y'all as I have no beef with that either way. |
No; the attack is not possible even if the proxy doesn't strip the header from the client (and just appends its own). We are checking for an exact
Yes, but anyone who follows this advice (including the official wordpress container, IIRC) is vulnerable.
For obvious reasons, an application won't do that until it confirms that a reverse proxy has been setup correctly. Once this is done, the attack is not possible...
True; we can first add the option (disabled by default) and mention in the documentation that it might be enabled by default someday. @tianon would that be accepted? if I'm not missing anything, it's just a file at |
Update: the |
When generating fully-qualified links and redirect URLs, php apps typically use server environment variable "HTTPS" to check whether to redirect to https or http. With apache this variable is set by mod_ssl (http://httpd.apache.org/docs/current/mod/mod_ssl.html#envvars).
If on other hand, SSL termination happens before the http request reaches the server where php is running then this information is lost, unless it's carried over, typically by x-forwarded-* headers.
With this change if request is e.g. forwarded to the docker container via mod_proxy in another apache:
Then dockerized php sees that $_SERVER[HTTPS]='on'.
In my usecase this was required for dockerized Drupal 8 to stop redirecting the user to http which wasn't even open in the firewall. (Typically proposed fix for this on SO and drupal forums is to add redirects to .htaccess which 1) wouldn't work unless port 80 was open, 2) is a potential security issue due to requests being made in cleartext, 3) POST request breaks if it receives a redirect response, 4) it's unnecessary and ugly.)