【问题标题】:Force SSL/https using .htaccess and mod_rewrite使用 .htaccess 和 mod_rewrite 强制 SSL/https
【发布时间】:2011-05-22 21:17:38
【问题描述】:

如何使用 PHP 中特定的 .htaccess 和 mod_rewrite 页面强制使用 SSL/https。

【问题讨论】:

    标签: php .htaccess mod-rewrite ssl https


    【解决方案1】:

    对于 Apache,您可以使用 mod_ssl 通过 SSLRequireSSL Directive 强制 SSL:

    该指令禁止访问,除非当前连接启用了 HTTP over SSL(即 HTTPS)。这在启用 SSL 的虚拟主机或目录中非常方便,可用于防御暴露应受保护的内容的配置错误。当此指令存在时,所有未使用 SSL 的请求都会被拒绝。

    虽然这不会重定向到 https。要重定向,请在 .htaccess 文件中使用 mod_rewrite 尝试以下操作

    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

    或在

    中给出的各种方法中的任何一种

    如果您的提供商禁用了 .htaccess,您也可以在 PHP 中解决此问题(这不太可能,因为您要求它,但无论如何)

    if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
        if(!headers_sent()) {
            header("Status: 301 Moved Permanently");
            header(sprintf(
                'Location: https://%s%s',
                $_SERVER['HTTP_HOST'],
                $_SERVER['REQUEST_URI']
            ));
            exit();
        }
    }
    

    【讨论】:

    • 这在我们的情况下非常好,因为我们目前混合了 http 和 https 流量。对于我们的管理区域,我们只是在 .htaccess 脚本中弹出,同时保持站点的其余部分为 http。
    • 当我使用 mod_rewrite 方法时,我被发送到 https 但出现“页面未正确重定向”错误。
    • 跟进:如果您遇到类似的问题,请检查您的服务器和 HTTP 变量。如果您的服务器使用代理,您可能需要使用 %{HTTP:X-Forwarded-Proto}%{HTTP:X-Real-Port} 变量来检查 SSL 是否打开。
    • 如果您在代理(CloudFlareOpenshift)后面运行的服务器上遇到重定向循环,请参阅this answer也适用于这种情况的解决方案。
    • @GTodorov - 删除空格打破了我的重写规则。根据我对重写规则的(有限)知识,语法是RewriteRule <input-pattern> <output-url>。因此,空间需要在那里,并且单个 ^ 只是说“匹配所有输入 URL”。
    【解决方案2】:

    我找到了一个mod_rewrite 解决方案,它适用于代理服务器和非代理服务器。

    如果您正在使用 CloudFlare、AWS Elastic Load Balancing、Heroku、OpenShift 或任何其他 Cloud/PaaS 解决方案,并且您在使用正常 HTTPS 重定向时遇到重定向循环,请尝试下面的 sn-p 代替。

    RewriteEngine On
    
    # If we receive a forwarded http request from a proxy...
    RewriteCond %{HTTP:X-Forwarded-Proto} =http [OR]
    
    # ...or just a plain old http request directly from the client
    RewriteCond %{HTTP:X-Forwarded-Proto} =""
    RewriteCond %{HTTPS} !=on
    
    # Redirect to https version
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

    【讨论】:

    • 这太棒了!但也许需要添加后置条件? RewriteCond %{REQUEST_METHOD} !^POST$
    • @Aleksej 没错,这会破坏未加密的 POST 请求。但我认为这是一件好事。这样,人们会注意到他们做错了什么。我想最好的办法是将他们重定向到一个页面,告知他们如何正确使用您的服务。
    • @raphinesse 你知道这个问题的答案吗:stackoverflow.com/questions/51951082/…
    【解决方案3】:

    PHP 解决方案

    直接从 Gordon 的非常全面的答案中借用,我注意到您的问题提到在强制 HTTPS/SSL 连接时是特定于页面的。

    function forceHTTPS(){
      $httpsURL = 'https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
      if( count( $_POST )>0 )
        die( 'Page should be accessed with HTTPS, but a POST Submission has been sent here. Adjust the form to point to '.$httpsURL );
      if( !isset( $_SERVER['HTTPS'] ) || $_SERVER['HTTPS']!=='on' ){
        if( !headers_sent() ){
          header( "Status: 301 Moved Permanently" );
          header( "Location: $httpsURL" );
          exit();
        }else{
          die( '<script type="javascript">document.location.href="'.$httpsURL.'";</script>' );
        }
      }
    }
    

    然后,在您希望通过 PHP 强制连接的这些页面的顶部附近,您可以 require() 包含此(和任何其他)自定义函数的集中文件,然后只需运行 forceHTTPS() 函数.

    HTACCESS / mod_rewrite 解决方案

    我还没有亲自实现过这种解决方案(我倾向于使用 PHP 解决方案,就像上面的那个,因为它很简单),但至少以下可能是一个好的开始。

    RewriteEngine on
    
    # Check for POST Submission
    RewriteCond %{REQUEST_METHOD} !^POST$
    
    # Forcing HTTPS
    RewriteCond %{HTTPS} !=on [OR]
    RewriteCond %{SERVER_PORT} 80
    # Pages to Apply
    RewriteCond %{REQUEST_URI} ^something_secure [OR]
    RewriteCond %{REQUEST_URI} ^something_else_secure
    RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    
    # Forcing HTTP
    RewriteCond %{HTTPS} =on [OR]
    RewriteCond %{SERVER_PORT} 443
    # Pages to Apply
    RewriteCond %{REQUEST_URI} ^something_public [OR]
    RewriteCond %{REQUEST_URI} ^something_else_public
    RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    

    【讨论】:

    • 出于好奇,为什么是RewriteCond %{REQUEST_METHOD} !^POST$
    • 因为 POST 参数不会保留在重定向中。如果您想确保所有 POST 提交都是安全的(任何不安全的 POST 提交都将被忽略),您可以省略该行。
    • @Lucanos - 如何编写一个不会在 POST 时强制重定向到 http 或 https 的 RewriteCond?我的 .htaccess 在某些特定页面上强制使用 HTTPS,然后在其余页面上强制使用 HTTP。但是,在 HTTPS 页面上,有些表单会提交到我的 Web 根目录。该表单将操作 url 指定为 HTTPS。但是,由于 Web 根不是指定强制使用 HTTPS 的页面之一,因此我的 .htaccess 会强制进行重定向——这意味着 POST 变量会丢失。如何防止 POST 上的重定向?
    • @StackOverflowNewbie:RewriteCond %{REQUEST_METHOD} !^POST$ 行应该防止 POST 提交受到这些重定向的影响。
    • 我喜欢这个 PHP 版本。它会更好,因为它考虑 POST 并且如果标头已经发送,则处理得更好。
    【解决方案4】:

    基于Mod-rewrite的解决方案:

    在 htaccess 中使用以下代码自动将所有 http 请求转发到 https。

    RewriteEngine on
    
    RewriteCond %{HTTPS}::%{HTTP_HOST} ^off::(?:www\.)?(.+)$
    RewriteRule ^ https://www.%1%{REQUEST_URI} [NE,L,R]
    

    这会将您的 非 wwwwww http 请求重定向到 www 版本的 https。

    另一种解决方案 (Apache 2.4*)

    RewriteEngine on
    
    RewriteCond %{REQUEST_SCHEME}::%{HTTP_HOST} ^http::(?:www\.)?(.+)$
    RewriteRule ^ https://www.%1%{REQUEST_URI} [NE,L,R]
    

    这不适用于较低版本的 apache,因为 %{REQUEST_SCHEME} 变量自 2.4 起已添加到 mod-rewrite。

    【讨论】:

      【解决方案5】:

      我只想指出,当跨目录深度使用多个 .htaccess 文件时,Apache 的继承规则最差。两个关键陷阱:

      • 默认情况下,只会执行最深的 .htaccess 文件中包含的规则。您必须指定 RewriteOptions InheritDownBefore 指令(或类似指令)才能更改此设置。 (see question)
      • 该模式应用于相对于子目录的文件路径,而不是包含具有给定规则的 .htaccess 文件的上层目录。 (see discussion)

      这意味着如果您在子目录中使用任何其他 .htaccess 文件,Apache Wiki 上建议的全局解决方案工作。我写了一个修改后的版本:

      RewriteEngine On
      # This will enable the Rewrite capabilities
      
      RewriteOptions InheritDownBefore
      # This prevents the rule from being overrided by .htaccess files in subdirectories.
      
      RewriteCond %{HTTPS} !=on
      # This checks to make sure the connection is not already HTTPS
      
      RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [QSA,R,L]
      # This rule will redirect users from their original location, to the same location but using HTTPS.
      # i.e.  http://www.example.com/foo/ to https://www.example.com/foo/
      

      【讨论】:

        【解决方案6】:

        简单易行,只需添加以下内容

        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
        

        【讨论】:

        • 这几乎就是互联网上的人们告诉你强制 https 做的事情。但是,每次我这样做时,我的整个网站都会被禁止或您无权查看。类似的东西......我做错了什么?我只是想知道您是否有任何想法,然后再发布有关此的问题。
        • 我遇到了类似的问题,我必须将规则应用于 https.conf 文件。请参阅下面的答案。
        【解决方案7】:

        此代码适用于我

        RewriteEngine On
        RewriteBase /
        RewriteCond %{HTTP:X-HTTPS} !1
        RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
        

        【讨论】:

          【解决方案8】:

          简单的一个:

          RewriteEngine on
          RewriteCond %{HTTP_HOST} ^(www\.example\.com)(:80)? [NC]
          RewriteRule ^(.*) https://example.com/$1 [R=301,L]
          order deny,allow
          

          将您的网址替换为 example.com

          【讨论】:

          • 不!网站 URL 必须是动态的。
          【解决方案9】:

          试试这个代码,它适用于所有版本的 URL,比如

          • website.com
          • www.website.com
          • http://website.com
          • http://www.website.com

            RewriteCond %{HTTPS} off
            RewriteCond %{HTTPS_HOST} !^www.website.com$ [NC]
            RewriteRule ^(.*)$ https://www.website.com/$1 [L,R=301]
            

          【讨论】:

            猜你喜欢
            • 2012-02-02
            • 2010-11-22
            • 2017-08-22
            • 2015-07-05
            • 2012-01-20
            • 2016-09-25
            • 2012-01-01
            • 2018-04-22
            相关资源
            最近更新 更多