【发布时间】:2011-05-22 21:17:38
【问题描述】:
如何使用 PHP 中特定的 .htaccess 和 mod_rewrite 页面强制使用 SSL/https。
【问题讨论】:
标签: php .htaccess mod-rewrite ssl https
如何使用 PHP 中特定的 .htaccess 和 mod_rewrite 页面强制使用 SSL/https。
【问题讨论】:
标签: php .htaccess mod-rewrite ssl https
对于 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:X-Forwarded-Proto} 或 %{HTTP:X-Real-Port} 变量来检查 SSL 是否打开。
RewriteRule <input-pattern> <output-url>。因此,空间需要在那里,并且单个 ^ 只是说“匹配所有输入 URL”。
我找到了一个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]
【讨论】:
直接从 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() 函数.
我还没有亲自实现过这种解决方案(我倾向于使用 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$?
RewriteCond %{REQUEST_METHOD} !^POST$ 行应该防止 POST 提交受到这些重定向的影响。
基于Mod-rewrite的解决方案:
在 htaccess 中使用以下代码自动将所有 http 请求转发到 https。
RewriteEngine on
RewriteCond %{HTTPS}::%{HTTP_HOST} ^off::(?:www\.)?(.+)$
RewriteRule ^ https://www.%1%{REQUEST_URI} [NE,L,R]
这会将您的 非 www 和 www 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。
【讨论】:
我只想指出,当跨目录深度使用多个 .htaccess 文件时,Apache 的继承规则最差。两个关键陷阱:
RewriteOptions InheritDownBefore 指令(或类似指令)才能更改此设置。 (see question)
这意味着如果您在子目录中使用任何其他 .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/
【讨论】:
简单易行,只需添加以下内容
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
【讨论】:
此代码适用于我
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP:X-HTTPS} !1
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
【讨论】:
简单的一个:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www\.example\.com)(:80)? [NC]
RewriteRule ^(.*) https://example.com/$1 [R=301,L]
order deny,allow
将您的网址替换为 example.com
【讨论】:
试试这个代码,它适用于所有版本的 URL,比如
RewriteCond %{HTTPS} off
RewriteCond %{HTTPS_HOST} !^www.website.com$ [NC]
RewriteRule ^(.*)$ https://www.website.com/$1 [L,R=301]
【讨论】: