简体   繁体   中英

Redirect Loop in PHP behind a Load Balancer with SSL

I have a situation where I'm getting stuck in an infinite redirect loop when I try to switch from SSL encrypted pages back to non-encrypted (https -> http). Our current configuration is set behind a load balancer that creates a header: HTTP_X_FORWARDED_PROTO

When it is set to SSL it returns "https", othwerise it always returns "http"

The following code I used to use on the site before the SSL cert was moved to the load balancer instead of the web node the site runs on. (HTTP_X_FORWARDED_PROTO) have been added to update the script accordingly.

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])){
    $redirect = '';
    if (!isset($sslPage)){
        $sslPage = false;
    }
    switch($_SERVER['HTTP_X_FORWARDED_PROTO']){
        case 'http' :
            if ($sslPage)
                $redirect = 'location: https://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
            break;  

        case 'https' :
            if (!$sslPage)
                //$redirect = 'location: http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
            break;
    }
    if (!empty($redirect)){
        header ($redirect); 
    }
}

Each page that needs ssl turned on has a preloaded variable of $sslPage = true;

So the redirect from http to https works great.. no issues. But if I try to go backwards it doesn't work. I get stuck in an endless loop. I'm starting to think that it's because of apache. Since the web node no longer terminates the SSL all traffic to it is run through port 80. When php is doing the redirect through header(), I believe what happens is the server gathers the request since it's local and tries to parse it. Since the HTTP_X_FORWARDED_PROTO is never updated because it didn't hit the load balancer again, the redirect can never be successul.

My question is if this makes sense or have I gone the wrong way with my thinking on this? Would this call regardless always get forwarded back to the load balancer? If it does stay internal to that web node, how do I force it to go back to the Load Balancer so it can write the new headers for the page it's trying to retrieve?

This has proven to be frustrating....

Thanks for your help in advance.

You could just let Apache think SSL is on by setting the environment variable (in PHP logic $_SERVER['HTTPS'] )

SetEnvIf X-Forwarded-Proto https HTTPS=On

This should allow your legacy code to work without the need to change.

We've just encountered something similar and discovered that it was our Zeus load balancer interfering with the response header. We discovered that any 301/302 headers sent back were being modified by the load balancer if the initial request had been made on https and the return was to a non-secure page.

For example, if client requested https://site.com and we redirected to http://site.com with a 302, the result back at the client end would have " Location: https://site.com " because the load balancer had switched it back (instead of the expected " Location: http://site.com ")

This was resolved by turning this feature off in the load balancer.

Hope that helps someone - it's a nasty issue to try and get to the bottom of!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM