【问题标题】:Cyclic redirection in htaccess: HTTPS -> HTTP rule is ignoredhtaccess 中的循环重定向:HTTPS -> HTTP 规则被忽略
【发布时间】:2015-01-24 16:45:48
【问题描述】:

第一部分

我在 htaccess 文件中有以下重写规则(在 OpehShift 服务器上):

RewriteEngine on

# Must NOT be SSL
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d [or]
RewriteCond %{REQUEST_URI} /
RewriteCond %{REQUEST_URI} !^/user/login
RewriteCond %{REQUEST_URI} !^/user/register
RewriteCond %{REQUEST_URI} !^/user/profile
RewriteCond %{REQUEST_URI} !^/user/captcha
RewriteRule (.*) http://%{SERVER_NAME}/$1 [last,redirect=permanent]

# MUST be SSL
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/user/login [or]
RewriteCond %{REQUEST_URI} ^/user/register [or]
RewriteCond %{REQUEST_URI} ^/user/captcha [or]
RewriteCond %{REQUEST_URI} ^/user/profile
RewriteRule (.*) https://%{SERVER_NAME}/$1 [last]

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php

目的是通过 SSL 处理一些路径,而所有其他路径应该可以通过普通 http 访问。最初设置这样的配置是一个挑战,但最终解决了 - 你可以在 OpenShift forums 上找到它的历史。

这在过去的某个时刻(可能是一些 OpenShift 更新)之前一直运行良好,当时它开始在 https 页面上循环循环:例如,当用户在他的个人资料页面上(使用 https)并单击链接以获取安全路径之外的页面,它一次又一次地尝试重定向到https

根据规则,如果不是登录、注册、个人资料或验证码页面,他们应该将https 更改为http,但这不会再发生了。可能是什么问题?提前致谢。

第二部分

尽管我接受了@anubhava 的回答(因为这似乎是 Apache 的问题,而不是我的问题,正如他在数小时的宝贵调试后所认为的那样),我仍在努力解决这个问题,并且任何进一步的解决方案/解决方法都非常重要欢迎。

同时问题归结为以下代码:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ - [env=ps:https]

RewriteCond %{HTTP:X-Forwarded-Proto} https
RewriteRule ^(.*)$ - [env=ps:http]

# known public pages
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/site/page/about
RewriteRule (.*) %{ENV:ps}://%{SERVER_NAME}/$1?ps=%{ENV:ps}&step=1 [last,redirect=permanent]

现在,当我转到 about 页面时,我得到了以下 http 标头:

HTTP/1.1 301 Moved Permanently
Date: Thu, 27 Nov 2014 15:07:27 GMT
Server: Apache/2.2.15 (Red Hat)
Location: https://mydomain.rhcloud.com/site/page/about?ps=http&step=1
Content-Length: 385
Content-Type: text/html; charset=iso-8859-1
Accept-Ranges: none
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive

请注意Locationhttps 原型,但ps 参数输出为http(如预期的那样)。如果这两个值都取自 ps 变量,这会怎样?恕我直言,这看起来很奇怪。

简而言之:从 https 到 http 的重定向在 OpenShift 服务器上不起作用。尽管规则说协议应该是http 服务器发送https - 因此循环重定向。

第三部分

也许我应该提到 OpenShift 站点使用 HAProxy 作为前端。它的配置不包含任何 ssl 特定设置。但我找到了this related answer,可能会读到:

最后,您将不会真正将人们从 HTTPS 连接中重定向出去,这被认为是不安全的,并且不支持

那么,HAProxy 是否总是隐含地将协议覆盖到https 以进行从安全页面进行的重定向?那么如何解决这个问题呢?

【问题讨论】:

    标签: .htaccess mod-rewrite https openshift haproxy


    【解决方案1】:

    不要使用REQUEST_URI,而是使用THE_REQUEST,因为您使用的是前端控制器。

    RewriteEngine on
    
    # Must NOT be SSL
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{HTTP:X-Forwarded-Proto} =https
    RewriteCond %{THE_REQUEST} !\s/+user/(login|register|profile|captcha) [NC]
    RewriteRule ^ http://%{SERVER_NAME}%{REQUEST_URI} [L,R=301,NE]
    
    # MUST be SSL
    RewriteCond %{HTTP:X-Forwarded-Proto} !=https
    RewriteCond %{THE_REQUEST} \s/+user/(login|register|profile|captcha) [NC]
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301,NE]
    
    # if a directory or a file exists, use it directly
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    # otherwise forward it to index.php
    RewriteRule . index.php
    

    【讨论】:

    • 感谢您的回答,但您的确切代码破坏了 CSS 样式。我将尝试仅使用 THE_REQUEST。
    • 在我的原始代码中使用 THE_REQUEST 而不是 REQUST_URI 不能解决无限 redictedtions 问题。
    • ok 查看更新的规则以解决 CSS 问题。如果它导致重定向循环,请在 Chrome 开发工具或 Firebug 中打开您的 https://domain.com/user/profile URL,然后查看您在 Net 选项卡中获得的重定向。
    • 它现在保留样式,但是当用户单击主页链接(/ 地址)时,它会获得带有https 的主站点页面,这是不正确的。此外,所有其他公共页面(例如 /site/page/about)都在尝试使用 https 显示并因循环重定向而失败。
    • 感谢您在聊天中的帮助。正如我们发现 openshift 齿轮似乎忽略了 https 值或没有以某种方式将其传递给 php
    【解决方案2】:

    最后我设法构建了一个解决方法,尽管我认为它并不优雅。如果你知道另一种方式,请告诉我。我的意思是一种方式 - 在 OpenShift 环境中工作。

    解决方案是使用.htaccess 仅处理一种方式重定向:从httphttps。从httpshttp 的重定向由客户端代码处理,该代码指示浏览器在不同的方案下重新加载页面。

    .htaccess

    RewriteEngine on
    
    # MUST be SSL
    RewriteCond %{HTTP:X-Forwarded-Proto} !https 
    RewriteCond %{THE_REQUEST} \s/+user/(login|register|profile|captcha)
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=302,NE]
    
    # if a directory or a file exists, use it directly
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # otherwise forward it to index.php 
    RewriteRule . index.php
    

    index.php

    ...
    require('switchhttp.php');
    ...
    

    切换http.php

    <?
    function redirect_url($url)
    {
      ?>
      <script>
      window.location.href="<? echo $url; ?>";
      </script>
      <?
    }
    
    $urls = array("/user/login", "/user/register", "/user/captcha", "/user/profile");
    $url = rawurldecode($_SERVER['REQUEST_URI']);
    
    if(!in_array($url, $urls) && isset($_SERVER['HTTPS']))
    {
      redirect_url("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
      exit;
    }
    ?>
    

    这对我有用。

    另外,我可能应该警告那些可能感兴趣的人,可以说 OpenShift 齿轮可能会意外地陷入“缓存状态”(也许这尤其与 HAProxy 有关)。在这种情况下,更新齿轮上的文件不会生效 - 您的浏览器,无论是否清除缓存,甚至是绝对新连接的客户端都会收到旧页面。调试非常令人沮丧。到目前为止,我发现解决此问题的唯一方法是重新启动您的设备。

    【讨论】:

    • 天哪,你必须走 PHP 路线才能完成它。希望openshift做出回应。 +1 努力
    • 奇怪的是,但维基百科上个月似乎使用了相同的方法:当我从谷歌的搜索结果导航后第一次打开一篇文章时,我简要地看到了它的http 版本,然后页面自动在https 下重新加载。
    • OpenShift 支持人员刚刚确认了我的建议,即免费计划用户的所有技术问题都应该在 StackOverflow 上发布。
    • 这很奇怪,显然他们的支持人员什么都不知道。
    猜你喜欢
    • 1970-01-01
    • 2013-04-09
    • 2023-03-25
    • 1970-01-01
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    相关资源
    最近更新 更多