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
1 | $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
1 | $this->redirect($this->request->referer($local = false)); |
Safer
1 2 3 4 5 6 | $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)
1 2 3 4 5 6 7 8 9 | $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:
1 2 3 4 5 6 7 8 9 10 11 12 | 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
1 | 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:
1 2 3 | # is passed to the backend as |
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
1 2 3 | # is passed to the backend as |
X-Forwarded-Proto Header Required
I found if I didn't set this header
1 | 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:
1 |
And then nginx would issue an internal redirect and mess-up the redirect
with the X-Forwarded-Proto header set it performed as required
1 |
0 Comments