CakePHP 4 $this->request->referer() not working in production

Written by James McDonald

June 24, 2020

Just had a situation where I couldn’t get a redirect to work. My CakePHP app is in an Apache enabled docker container behind an nginx reverse proxy

$this->redirect($this->request->referer());

The above simply refused to work in my development environment it worked fine

http://localhost:8090/blah/ worked fine

But

http://example.com/blah/

and it would return nothing

It turned out that if your hostnames don’t match i.e. your front end is accessed via https://example.com/blah and your backend is accessed via http://localhost:8090/blah then a call to $request->referer() return bupkis

This works although I imagine some sanitizing needs to be done to stop it just accepting any forged referer URL

$this->redirect($this->request->referer($local = false));

Safer


$referer = $this->request->referer(false);
if( preg_match('example.com', $referer ) === 1 ) {
     return $this->redirect($referer);
} else {
     return $this->redirect([ 'action' => 'index' ]);
}

Taking into account a trusted proxy (i.e. it can tell you what the external http_host name is)

        $this->request->trustProxy = true;
        $referer = $this->request->referer($local = false);
        $host = $this->request->host(); 
        $scheme = $this->request->scheme();

        if (preg_match('/^' . $scheme . ':\/\/' . $host . '/', $referer) === 1) {
            return $this->redirect($referer);
        }
        return $this->redirect(['action' => 'index']);

Nginx Configuration

Note I’m only trusting this because nginx is setting the headers:

upstream my-test {
    server 127.0.0.1:8999;
}
location /test {
    proxy_pass http://my-test;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
    proxy_set_header X-Forwarded-Proto https;
}

Notes about this nginx config

Front end running https Backend running http

This nginx frontend server block is running ssl enabled

The backend is running only http so specify http:// to upstream

proxy_pass http://my-test;

Proxy Pass Trailing Slash or Lack of it Changes the Behavior

Without a trailing slash

If you specify no trailing forward slash then the location and all subsequent pieces are passed. For example a request made to the front end nginx to:

https://example.com/test/controller/action
# is passed to the backend as
http://127.0.0.1:8999/test/controller/action

With a trailing slash

if you specify proxy_pass http://my-test/; a request to https://example.com/test/controller/action will be passed on without the location /test parameter

https://example.com/test/controller/action
# is passed to the backend as
http://localhost:8999/controller/action

X-Forwarded-Proto Header Required

I found if I didn’t set this header

proxy_set_header X-Forwarded-Proto https;

Then after I posted a delete e.g. POST /test/controller/delete/23 the 302 redirect issued to the client would have the wrong scheme in the location header:

location: http://example.com/test/controller/action

And then nginx would issue an internal redirect and mess-up the redirect

with the X-Forwarded-Proto header set it performed as required

location: https://example.com/test/controller/action

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.

You May Also Like…

Squarespace Image Export

To gain continued access to your Squarespace website images after cancelling your subscription you have several...

MySQL 8.x GRANT ALL STATEMENT

-- CREATE CREATE USER 'tgnrestoreuser'@'localhost' IDENTIFIED BY 'AppleSauceLoveBird2024'; GRANT ALL PRIVILEGES ON...

Exetel Opt-Out of CGNAT

If your port forwards and inbound and/or outbound site-to-site VPN's have failed when switching to Exetel due to their...