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

#1 楼

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


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


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

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





http://www.askapache.com/htaccess/http-https-rewriterule-redirect.html

如果您的提供者禁用了.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。

–迈克尔·J·卡尔金斯(Michael J. Calkins)
2014-09-24 23:11

当我使用mod_rewrite方法时,会发送到https,但出现“页面无法正确重定向”错误。

–捷克文
2014年10月9日12:00

后续:如果遇到类似的问题,请检查服务器和HTTP变量。如果服务器使用代理,则可能要使用%{HTTP:X-Forwarded-Proto}或%{HTTP:X-Real-Port}变量来检查SSL是否已打开。

–捷克文
2014年10月9日,12:47

如果您在代理后面运行的服务器(CloudFlare,Openshift)上遇到重定向循环,请参阅此答案以获取适用于这种情况的解决方案。

–raphinesse
2015年12月3日,11:58



@GTodorov-删除空间为我破坏了重写器。以我对重写器的有限了解,语法为RewriteRule 。因此,必须在该空间,并且单个^表示“匹配所有输入URL”。

– Sphinxxx
16年6月30日在13:37

#2 楼

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

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

 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
17年9月16日在9:40



@Aleksej是的,这破坏了未加密的POST请求。但是我认为这是一件好事。这样,人们会注意到他们在做错事。我想最好的办法是将它们重定向到一个页面,该页面告知他们如何正确使用您的服务。

–raphinesse
18 Mar 20 '18在11:53

@raphinesse你知道这个问题的答案:stackoverflow.com/questions/51951082/…

– RNN
18年8月21日在14:37

#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 $?

– depoulo
13年6月29日在6:43

因为POST参数未保留在重定向中。如果要确保所有POST提交都是安全的,则可以省略该行(任何不安全的POST提交都将被忽略)。

–路易斯·史蒂文森(Luke Stevenson)
13年6月30日在6:35

@Lucanos-如何编写一个POST时不强制重定向到http或https的RewriteCond?我的.htaccess会在某些特定页面上强制使用HTTPS,然后在其余页面上强制使用HTTP。但是,在HTTPS页面上,有一些表单可以提交到我的Web根目录。该表格将操作网址指定为HTTPS。但是,由于Web根目录不是指定用于强制HTTPS的页面之一,因此我的.htaccess会强制进行重定向-这意味着POST变量会丢失。如何防止POST上的重定向?

– StackOverflowNewbie
2014年7月8日在19:23

@StackOverflowNewbie:RewriteCond%{REQUEST_METHOD}!^ POST $这一行应该防止POST提交受到这些重定向的影响。

–路易斯·史蒂文森(Luke Stevenson)
2014年7月9日在6:15



我喜欢这个PHP版本。考虑到POST会更好,并且如果已经发送了标头,则处理会更好。

– TheStoryCoder
16-2-29在10:38

#4 楼

基于Mod重写的解决方案:

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

RewriteEngine on

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


这将重定向您的非-www和www http请求https的www版本。

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

RewriteEngine on

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


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

#5 楼

我只想指出,在跨目录深度使用多个.htaccess文件时,Apache具有最差的继承规则。两个主要陷阱:默认情况下,仅执行最深.htaccess文件中包含的规则。您必须指定RewriteOptions InheritDownBefore指令(或类似指令)才能更改此设置。 (请参阅问题)

该模式应用于相对于子目录的文件路径,而不应用于包含具有给定规则的.htaccess文件的上层目录。 (请参阅讨论)。这意味着如果您在子目录中使用任何其他.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的行为。但是,每次这样做,我的整个网站都会被禁止或您无权查看。诸如此类...我在做什么错?我只想知道您是否有任何想法,然后再对此发表问题。

– ThN
18/12/14在13:53

我有一个类似的问题,我不得不将规则应用于https.conf文件。请参阅下面的答案。

–Risteard
19年7月2日在10:19

#7 楼

该代码对我有用

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


#8 楼

简单的一个:

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


用example.com替换您的网址

评论


没有!网站网址必须是动态的。

–阿米尔·萨凡德(Amir Savand)
18年8月23日在12:08

#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/ [L,R=301]