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