CakePHP (all versions that I've seen) check against $_SERVER['HTTPS']
to see whether a request has been made over HTTPS instead of plain HTTP.
I'm using nginx as a load balancer, behind which are the Apache application servers. Since the SSL connection terminates at the load balancer, $_SERVER['HTTPS']
is not set as far as CakePHP is concerned.
I'd like to find a secure way to detect HTTPS on the app servers.
So far, I've put this into my CakePHP configuration:
$request_headers = getallheaders();
if ( (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) || ( isset($request_headers['X-Forwarded-Proto']) && $request_headers['X-Forwarded-Proto'] == 'https' ) ) {
$ssl = true;
// overwrite environment vars (ugly) since CakePHP won't honour X-Forwarded-Proto
$_SERVER['HTTPS'] = 'on';
$_ENV['HTTPS'] = 'on';
} else {
$ssl = false;
}
And then in the nginx configuration, I've used proxy_set_header X-Forwarded-Proto https;
to add the flag to any requests between the load balancer and the back-end application servers.
This works perfectly fine, but anyone making a direct request to the app servers could fool them into thinking they are browsing over SSL when they're not. I'm not sure whether this is a security risk, but it doesn't seem like a good idea.
Is it a security risk? What's the better solution?
Since using X-Forwarded-Proto
seems like something of a standard, the solution may be a good patch to be submitted to the CakePHP core, so I think any answer can legitimately involve editing core files too.
NGINX is open source software for web serving, reverse proxying, caching, load balancing, media streaming, and more. It started out as a web server designed for maximum performance and stability.
Do not edit the core. If your intention is to submit a patch, don't rely on your patch until after it's accepted - Otherwise you're on a road to divergence and maintaining your own fork of CakePHP.
Once you determine your exact implementation logic you can use a request detector to honor it.
for example:
//AppController::beforeFilter
public function beforeFilter() {
$this->request->addDetector('ssl', array(
'env' => 'HTTP_X_FORWARDED_PROTO',
'value' => 'https'
));
}
After this, your custom header will correctly be identified by cake as an ssl request.
Note that the keys of the $_SERVER
global are normalized as all caps and underscore delimited i.e.:
$ curl --header "X-Forwarded-Proto:https" http:://yoursite.com
Will populate $_SERVER['HTTP_X_FORWARDED_PROTO']
- as such this is the key to check for.
Yes, it's something you should take care of - either disable direct
access to your webservers so that only via the ip of the loadbalancer will it respond at all; or modify your detector so that it does not return true for direct-access requests
irrespective of the value of the X-Forwarded-Proto
header - as shown in the documentation you can use a callback to perform whatever logic required rather than simply testing the values of some environment variable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With