0
votes

I'm having issues with a new Laravel app behind a load balancer. I would like to have Laravel do the Auth middleware 302 redirects to relative path like /login instead of the http://myappdomain.com/login is actually doing.

I only see 301 redirects in the default .htaccess Laravel ships which makes me believe the behavior is right within Laravel, am I wrong?

Can someone point me in the right direction?

1
What are you trying to solve with this?apokryfos
I have the app behind a load balancer. The load balancer receives https and sends http to my app. The problem is that my app is redirecting the user to login with the absolute url, meaning replacing HTTPS with HTTP. If I put a redirect from HTTP to HTTPS in the load balancer then I get too many redirects issue.Mario
This is an XY problem. The correct way to deal with this is to do e.g. $request->setTrustedProxies([ /* IPs of your load balancers */ ]) . Properly configured load balancers send a X-Forwarded-Proto which laravel can use to determine the correct protocol as long as the header is coming from a trusted source. Check stackoverflow.com/questions/28402726/… for more detailsapokryfos
Thank you @apokryfos. Makes totally sense, I will test this suggestion right away. Although I'm still curious about the absolute/relative path which I think is more like a preference of the framework. I have a similar app with Zend Framework that does redirects with relative paths. I will report back the result, thanks one more time.Mario
Relative redirects might be problematic if you're serving the framework from a subfolder e.g. from example.com/subfolder/apokryfos

1 Answers

0
votes

If you need to properly determine whether a request was secure when behind a load balancer you need to let the framework know that you're behind a proxy. This will ensure that the route() and url() helpers generate correct URLs and remove the need to create relative redirects which are both not 100% supported by browsers and also won't work properly when serving a webpage from a sub-path.

This is what we use to solve this problem and it's working so far for us:

.env

LOAD_BALANCER_IP_MASK=aaa.bbb.ccc.ddd/xx #Subnet mask

LoadBalanced Middleware

class LoadBalanced { 
      public function handle($request, $next) {
          if (env("LOAD_BALANCER_IP_MASK")) {
             $request->setTrustedProxies([ env("LOAD_BALANCER_IP_MASK") ]);
          }
          $next($request);
     }
}

Then put the middleware in your Kernel.php:

protected $middleware = [ 
    LoadBalanced::class,
    //.... It shouldn't matter if it's first or last as long as other global middleware don't need it

];

This is a feature available to Laravel because it is using the Symfony request as a base. How this work is that the load balancer forwards some important headers. Symfony currently understands:

 protected static $trustedHeaders = array(
    self::HEADER_FORWARDED => 'FORWARDED',
    self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
    self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
    self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
    self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
);

which have information regarding the user making the request to the load balancer and the protocol used.

Also according to framework comments:

The FORWARDED header is the standard as of rfc7239.

The other headers are non-standard, but widely used by popular reverse proxies (like Apache mod_proxy or Amazon EC2).

Update:

Since version 5.5, the Laravel boilerplate package includes the TrustedProxy middleware which uses the fideloper/TrustedProxy package.

To have it working you need to (a) make sure it's in your $middleware array in your App\Http\Kernel class and that you place the IPs of the trusted proxies in this middleware e.g.

protected $proxies = [
   '1.2.3.4'
];

I would highly recommend to explicitly specify which forwarded headers your proxy sends e.g.:

protected $headers = Request::HEADER_X_FORWARDED_AWS_ELB;

if you're using an AWS load balancer.

The reason for this is quite important in that if you are using an AWS load balancer then someone could craft a request with the 'Forwarded` header and that will be forwarded by AWS and then processed by the middleware essentially allowing users to spoof their IP host/port etc.