使用.htaccess和mod_rewrite强制SSL/https

San*_*hah 228 php .htaccess mod-rewrite ssl https

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

Gor*_*don 426

对于Apache,您可以使用以下mod_ssl命令强制使用SSL SSLRequireSSL Directive:

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

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

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Run Code Online (Sandbox Code Playgroud)

或者给出的任何一种方法

如果您的提供商已禁用.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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 跟进:如果遇到类似问题,请检查服务器和HTTP变量.如果您的服务器使用代理,您可能希望使用`%{HTTP:X-Forwarded-Proto}或'%{HTTP:X-Real-Port}'变量来检查SSL是否已打开. (11认同)
  • 如果您在代理服务器后运行的服务器上遇到**重定向循环**(*CloudFlare*,*Openshift*),请参阅[此答案](http://stackoverflow.com/a/34065445/380229)获取适用于那个案子也是. (8认同)
  • 喜欢CloudFlare (4认同)
  • @GTodorov - 删除空间打破了我的重写.根据我的(有限的)rewriterules知识,语法是`RewriteRule <input-pattern> <output-url>`.因此,空间需要存在,单个`^`只是说"匹配所有输入的URL". (4认同)

rap*_*sse 53

我找到了一个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]
Run Code Online (Sandbox Code Playgroud)


Luk*_*son 36

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>' );
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,在靠近要强制通过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]
Run Code Online (Sandbox Code Playgroud)

  • 因为POST参数不会保留在重定向上.如果要确保所有POST提交都是安全的,则可以省略该行(将忽略任何不安全的POST提交). (12认同)

sta*_*een 10

基于Mod-rewrite的解决方案:

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

RewriteEngine on

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

这会将您的非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]
Run Code Online (Sandbox Code Playgroud)

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


lpd*_*lpd 8

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

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

这意味着对建议的全球性解决方案的Apache维基没有,如果你在子目录中使用任何其他的.htaccess文件.我写了一个修改后的版本:

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/
Run Code Online (Sandbox Code Playgroud)