Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I securely detect SSL in CakePHP behind an nginx reverse proxy?

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.

like image 504
Aaron Pollock Avatar asked Jan 13 '13 14:01

Aaron Pollock


People also ask

What can Nginx do?

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.


1 Answers

Add a request detector

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.

Account for (in)security

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.

like image 142
AD7six Avatar answered Oct 21 '22 10:10

AD7six