开发者

Https causing redirect loop?

I am using code igniter, our server is behind some funky config.

I want certian pages to be behind https, certian pages to be behind http, and others I don't care about.

So below is my setup,

  • If I go to http://test.example.com (which has a call to disable_ssl()) the page loads fine
  • If I go to https://test.example.com/login (which has a call to require_ssl()) the page loads fine.
  • If I go the http://test.example.com/login I get redirected to the https version. which is good.
  • If I go to https://test.example.com then I get hit with a redirect loop... For some reason the header keeps getting set to https instead of http, even though I explicitly write http.

My $_SERVER array on an http request looks like looks like

Array
(
    [REDIRECT_STATUS] => 200
    [HTTP_HOST] => test.example.com:80
    [HTTP_X_REAL_IP] => 119.224.22.142
    [HTTP_X_FORWARDED_FOR] => 119.224.22.142
    [HTTP_X_URL_SCHEME] => http
    [HTTP_CONNECTION] => close
    [HTTP_CACHE_CONTROL] => max-age=0
    [HTTP_USER_AGENT] => Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8
    [HTTP_ACCEPT_ENCODING] => gzip,deflate,sdch
    [HTTP_ACCEPT_LANGUAGE] => en-US,en;q=0.8,en-NZ;q=0.6
    [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.3
    [HTTP_COOKIE] => [...]
    [PATH] => /usr/local/bin:/usr/bin:/bin
    [SERVER_SIGNATURE] => 
Apache/2.2.14 (Ubuntu) Server at test.example.com Port 8080


    [SERVER_SOFTWARE] => Apache/2.2.14 (Ubuntu)
    [SERVER_NAME] => test.example.com
    [SERVER_ADDR] => 127.0.0.1
    [SERVER_PORT] => 8080
    [REMOTE_ADDR] => 127.0.0.1
    [DOCUMENT_R开发者_高级运维OOT] => /var/www
    [SERVER_ADMIN] => webmaster@localhost
    [SCRIPT_FILENAME] => /var/www/index.php
    [REMOTE_PORT] => 54833
    [REDIRECT_URL] => /
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.0
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /
    [SCRIPT_NAME] => /index.php
    [PATH_INFO] => /
    [PATH_TRANSLATED] => redirect:/index.php/
    [PHP_SELF] => /index.php/
    [PHP_AUTH_USER] => ******
    [PHP_AUTH_PW] => ******
    [REQUEST_TIME] => 1308972068
)

and on a https request it looks like

Array
(
    [REDIRECT_STATUS] => 200
    [HTTP_HOST] => test.example.com:443
    [HTTP_X_REAL_IP] => 119.224.22.142
    [HTTP_X_FORWARDED_FOR] => 119.224.22.142
    [HTTP_X_URL_SCHEME] => https
    [HTTP_X_FORWARDED_PROTO] => https
    [HTTP_CONNECTION] => close
    [HTTP_USER_AGENT] => Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8
    [HTTP_ACCEPT_ENCODING] => gzip,deflate,sdch
    [HTTP_ACCEPT_LANGUAGE] => en-US,en;q=0.8,en-NZ;q=0.6
    [HTTP_ACCEPT_CHARSET] => ISO-8859-1,utf-8;q=0.7,*;q=0.3
    [HTTP_COOKIE] => [...]
    [PATH] => /usr/local/bin:/usr/bin:/bin
    [SERVER_SIGNATURE] => 
Apache/2.2.14 (Ubuntu) Server at test.example.com Port 8080


    [SERVER_SOFTWARE] => Apache/2.2.14 (Ubuntu)
    [SERVER_NAME] => test.example.com
    [SERVER_ADDR] => 127.0.0.1
    [SERVER_PORT] => 8080
    [REMOTE_ADDR] => 127.0.0.1
    [DOCUMENT_ROOT] => /var/www
    [SERVER_ADMIN] => webmaster@localhost
    [SCRIPT_FILENAME] => /var/www/index.php
    [REMOTE_PORT] => 54841
    [REDIRECT_URL] => /
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.0
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /
    [SCRIPT_NAME] => /index.php
    [PATH_INFO] => /
    [PATH_TRANSLATED] => redirect:/index.php/
    [PHP_SELF] => /index.php/
    [PHP_AUTH_USER] => ********
    [PHP_AUTH_PW] => ********
    [REQUEST_TIME] => 1308972250
)

and my .htaccess looks like

Options +FollowSymlinks
RewriteEngine on

RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ %1/$1 [R=301,L]


RewriteCond $1 !^(index\.php|robots\.txt|favicon\.ico|css|images|js)
RewriteRule ^(.*)$ index.php/$1 [L] 

So at the very top of my index.php I have

$_SERVER['SERVER_PORT'] = explode(':', $_SERVER['HTTP_HOST']);
$_SERVER['HTTP_HOST'] = $_SERVER['SERVER_PORT'][0];
$_SERVER['SERVER_PORT'] = $_SERVER['SERVER_PORT'][1];
if($_SERVER['SERVER_PORT'] == 443)
  $_SERVER['HTTPS'] = 'On';
else
  $_SERVER['HTTPS'] = 'Off';

And on pages where I want HTTPS I call

function require_ssl(){
    if($_SERVER['HTTPS'] == 'Off') {
        $host = explode(':', $_SERVER['HTTP_HOST']);
        header('location: https://' . $host[0] . $_SERVER['REQUEST_URI']);
        exit;
    }
}

And on pages where I want only HTTP I call

function disable_ssl(){
    if($_SERVER['HTTPS'] == 'On') {
        $host = explode(':', $_SERVER['HTTP_HOST']);
        header('location: http://' . $host[0] . $_SERVER['REQUEST_URI']);
        exit;
    }
}


So, after hours of painful debugging we finally worked out the issue.

Nginx
Yep, the load balancer was doing it's own redirects.

In the nginx setup this line existed proxy_redirect http:// https://;

So, what was happening?

Well, My code was saying "this page should not be https, redirect"
Then nginx was saying "this request is not https, redirect"
Then my code was...
boom redirect loop.

So, by changing proxy_redirect http:// https://; to proxy_redirect Off; we fixed the problem :)


The function that you posted for disable_ssl() shows:

if($_SERVER['HTTPS'] == '0n') {

Is the 0 ('zero') a copy/paste error? I assume that you meant:

if($_SERVER['HTTPS'] == 'On') {

If I'm following your logic correctly, this function is invoked when you goto https://test.example.com, and so if this typo exists, it is probably not doing what you think it should.


We've addressed the accurate fix for Nginx (and other reverse proxies) here:

http://www.sonassi.com/knowledge-base/magento-kb/magento-https-redirect-loop/

This avoids the necessity to have that code in your index.php file. All you needed to do was add this to your Nginx config,

fastcgi_param  HTTPS on;


You might consider using .htaccess rules instead, something like:

RewriteCond %{SERVER_PORT} 80 
RewriteCond %{REQUEST_URI} (optional pattern additional url matching)
RewriteRule ^(.*)$ https://test.example.com/$1 [L]

if you want to force http just replace 80 with 443 and https with http.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜