如何强制用户通过HTTPS而非HTTP访问我的页面?


137

我只有一个页面要强制作为HTTPS页面(Apache上的PHP)进行访问。如何在不使整个目录都需要HTTPS的情况下执行此操作?或者,如果您从HTTP页面向HTTPS页面提交表单,它是通过HTTPS而不是HTTP发送的吗?

这是我的示例:

http://www.example.com/some-page.php

我希望只能通过以下方式访问它:

https://www.example.com/some-page.php

当然,我可以将指向此页面的所有链接都指向HTTPS版本,但这并不能阻止一些傻瓜故意通过HTTP访问它...

我想到的一件事是在PHP文件的标头中放置一个重定向,以检查它们是否正在访问HTTPS版本:

if($_SERVER["SCRIPT_URI"] == "http://www.example.com/some-page.php"){
  header('Location: https://www.example.com/some-page.php');
}

但这不是正确的方法,对吗?



3
有什么理由为什么您不只要求所有页面都使用SSL?
Tahaan 2015年

Answers:


177

我以前做过的方式基本上就像您写的一样,但是没有任何硬编码的值:

if($ _ SERVER [“ HTTPS”]!=“ on”)
{
    header(“ Location:https://”。$ _SERVER [“ HTTP_HOST”]。$ _SERVER [“ REQUEST_URI”]));
    出口();
}

15
您忘记了调用exit()来确保脚本在重定向后退出。我通常将其包装在一个名为requireSSL()的函数中。我可以在要加密的任何页面的顶部调用此命令。
杰西·魏格特2009年

31
更改是否为(empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")修复PHP通知。
dave1010 2013年

$_SERVER[]变量是否不会因用户干预而改变/受到影响?
阿里安·福托什

@ArianFaurtosh来源?
约翰

3
@ArianFaurtosh有些是从客户端头提取,像HTTP_X_FORWARDED,和可以被操纵,但其他类似HTTPSSERVER_PORT直接从Web服务器设置,并应通常是安全的。
马恩

46

您可以在Apache上使用指令和mod_rewrite来实现:

<Location /buyCrap.php>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</Location>

如果需要,您可以使用正则表达式使位置信息随着时间的推移变得更智能。


6
你会把它放在哪里?.htaccess文件?

1
REQUEST_URI是否不包含“查询字符串”(例如?page = 1&id = 41等)?那就是apache文档所说的...所以,如果我尝试访问site.com/index.php?page=1&id=12,我将被重定向到site.com/index.php
Rolf

2
从apache文档中:REQUEST_URI请求的URI的路径部分,例如“ /index.html”。这特别排除了查询字符串,该查询字符串可以作为其自己的名为QUERY_STRING的变量使用。因此,您需要在REQUEST_URI之后添加QUERY_STRING
Rolf

2
您还需要在其后添加[R]标志,以使其重定向
Rolf

40

您应强制客户端始终使用HTTP Strict Transport Security(HSTS)标头请求HTTPS :

// Use HTTP Strict Transport Security to force client to use secure connections only
$use_sts = true;

// iis sets HTTPS to 'off' for non-SSL requests
if ($use_sts && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
    header('Strict-Transport-Security: max-age=31536000');
} elseif ($use_sts) {
    header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301);
    // we are in cleartext at the moment, prevent further execution and output
    die();
}

请注意,大多数现代浏览器都支持HSTS,但不是通用浏览器。因此,以上逻辑在用户不依赖于HTTP的情况下手动重定向用户,无论他们是否支持HTTP,然后设置HSTS标头,以便在可能的情况下由浏览器重定向其他客户端请求。


我很惊讶,没有其他答案包含此标头,这很重要……将两者结合起来有什么陷阱吗?
keisar

不...如果您始终需要HTTPS,则绝对可以设置该标头。在执行重定向之前和之后进行设置只是多余的。我还修改了上面的答复,以更准确地解释兼容性。
Jacob Swartwood

1
(编辑原始评论)我没有注意到“仅一页”的具体要求。HSTS将适用于所有页面;我的回答在技术上是不正确的。
Jacob Swartwood

4
仅供参考,标准RFC 6797第7.2节说:“ HSTS主机不得在通过非安全传输传送的HTTP响应中包含STS头字段。” 因此,当请求为常规http时,无需发送它,如果浏览器遵循标准,则应将其忽略。
Frank Forte

1
@mark,如果有一个MITM并且您的网站没有此标头,则可以允许包含的会话转到http,而人们输入其详细信息,他们可能不会注意到,并且重定向也无济于事(中间人将通过https连接到该网站,并将其显示为http)。使用此标头将在客户端强制HTTPS。由于最近的WPA2 WiFi安全漏洞,这一点尤其重要。
Rudiger

19

我刚刚创建了一个.htaccess文件并添加了:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

很简单!


9
// Force HTTPS for security
if($_SERVER["HTTPS"] != "on") {
    $pageURL = "Location: https://";
    if ($_SERVER["SERVER_PORT"] != "80") {
        $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
    } else {
        $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
    }
    header($pageURL);
}

8

在负载平衡器后面运行时,必须执行类似的操作。帽子提示https://stackoverflow.com/a/16076965/766172

function isSecure() {
    return (
        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
     || $_SERVER['SERVER_PORT'] == 443
     || (
            (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
         || (!empty($_SERVER['HTTP_X_FORWARDED_SSL'])   && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on')
        )
    );
}

function requireHTTPS() {
    if (!isSecure()) {
        header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], TRUE, 301);
        exit;
    }
}

6

PHP方式:

$is_https=false;
if (isset($_SERVER['HTTPS'])) $is_https=$_SERVER['HTTPS'];
if ($is_https !== "on")
{
    header("Location: https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
    exit(1);
}

Apache mod_rewrite方式:

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

我更喜欢PHP方式,因为在某些情况下,我希望覆盖对SSL的要求。例如,本地访问API以及诸如Mozilla Thunderbird的自动配置之类的东西。–
Jay

强烈建议您使用PHP方法。
Moxet Jan

5

http://www.besthostratings.com/articles/force-ssl-htaccess.html

有时您可能需要确保用户正在通过安全连接浏览您的站点。始终将用户重定向到安全连接(https://)的简单方法可以通过包含以下行的.htaccess文件来实现:

RewriteEngine On 
RewriteCond %{SERVER_PORT} 80 
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

请注意,.htaccess文件应位于网站的主文件夹中。

如果您希望对特定文件夹强制使用HTTPS,则可以使用:

RewriteEngine On 
RewriteCond %{SERVER_PORT} 80 
RewriteCond %{REQUEST_URI} somefolder 
RewriteRule ^(.*)$ https://www.domain.com/somefolder/$1 [R,L]

.htaccess文件应放置在需要强制使用HTTPS的文件夹中。


5

好的,现在有很多东西,但是没有人真正完成“安全”问题。对我来说,使用不安全的东西是荒谬的。

除非您将其用作诱饵。

$ _SERVER传播可以知道某人的意愿进行更改。

就像Sazzad Tushar Khan和thebigjc所说的那样,您也可以使用httaccess来做到这一点,并且这里有很多答案。

只需添加:

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://example.com/$1 [R,L]

到.httaccess中所有内容的结尾,就是这样。

仍然我们不像使用这两个工具那样安全。

其余的很简单。如果缺少属性,即...

if(empty($_SERVER["HTTPS"])){ // SOMETHING IS FISHY
}

if(strstr($_SERVER['HTTP_HOST'],"mywebsite.com") === FALSE){// Something is FISHY
}


还要说您已经更新了httaccess文件并检查:

if($_SERVER["HTTPS"] !== "on"){// Something is fishy
}

您可以检查更多变量,即。

HOST_URI (如果要检查静态属性)

HTTP_USER_AGENT (同一会话的不同值)

因此,我的意思是,当答案组合在一起时,不要仅仅满足于一个或另一个。

有关更多httaccess重写信息,请参阅docs-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

此处的某些堆栈-> 使用.htaccess和mod_rewrite强制SSL / https,

获取完整的URL。当前页面(PHP)
仅举几例。


2
但现在出现以下错误:ERR_TOO_MANY_REDIRECTS。我该如何解决?
Pathros

3

$_SERVER['HTTPS']说,如果它是SSL,并重定向到正确的地方,如果没有。

请记住,显示表单的页面不需要通过HTTPS进行馈送,这是最需要它的回发URL。

编辑:是的,正如下面所指出的,最好将整个过程放在HTTPS中。更为令人放心的是-我指出,帖子是最关键的部分。另外,您需要注意将所有cookie设置为安全的,因此它们只会通过SSL发送。mod_rewrite解决方案也很漂亮,我用它来保护自己网站上的许多应用程序。


的确,表单本身不需要是https,尽管对于大多数不知道这一点的人来说这是一个好主意。如果他们要提交表单并发现锁图标不存在,他们可能会错误地认为表单不安全。
Graeme Perrow

1
@Graeme:此外,没有人可以确保表单将通过https发送。整个表单(通过http显示)可能是伪造的,并提交到未知或http明文网站。Https不仅涉及加密,还对服务器进行身份验证。
Olaf Kock

3

用途htaccess

#if domain has www. and not https://
  RewriteCond %{HTTPS} =off [NC]
  RewriteCond %{HTTP_HOST} ^(?i:www+\.+[^.]+\.+[^.]+)$
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [QSA,L,R=307]

#if domain has not www.
  RewriteCond %{HTTP_HOST} ^([^.]+\.+[^.]+)$
  RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [QSA,L,R=307]

1

不要在同一页面上混合使用HTTP和HTTPS。如果您有一个通过HTTP提供的表单页面,那么我将对提交数据感到不安-如果不执行查看源并进行搜寻,就无法查看提交是通过HTTPS还是HTTP进行的。

通过HTTPS连同提交链接一起提供表单并没有太大的优势。


1

如果您使用Apache或支持.htaccess文件的LiteSpeed之类的工具,则可以执行以下操作。如果还没有.htaccess文件,则应在根目录(通常是index.php所在的位置)中创建一个新的.htaccess文件。现在,将这些行添加为.htaccess中的第一个重写规则:

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

对于所有重写规则,您仅需要在.htaccess中使用一次“ RewriteEngine On”指令,因此,如果已经有了它,则只需复制第二行和第三行即可。

我希望这有帮助。


这是对我有用的东西,也是我在类似于Zend 2的Framework上自己的脚本中使用的东西-我不理解这种不赞成。
安东尼奥

也许你已经downvoted,因为答案几乎是相同的这一个从@MatHatrik被张贴超过去年同期?
Wilt

1

仅使用此功能还不够:

if($_SERVER["HTTPS"] != "on")
{
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
    exit();
}

如果您有任何http内容(例如外部http图像源),则浏览器将检测到可能的威胁。因此,请确保您代码中的所有ref和src均为https


1

我已经通过许多解决方案来检查$ _SERVER [HTTPS]的状态, 但似乎不可靠,因为有时它没有设置或设置为on,off等,从而导致脚本进行内部循环重定向。

如果您的服务器支持$ _SERVER [SCRIPT_URI],这是最可靠的解决方案

if (stripos(substr($_SERVER[SCRIPT_URI], 0, 5), "https") === false) {
    header("location:https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
    echo "<meta http-equiv='refresh' content='0; url=https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]'>";
    exit;
}

请注意,根据您的安装,您的服务器可能不支持$ _SERVER [SCRIPT_URI],但如果支持,则是更好的脚本。

您可以在此处检查:为什么某些PHP安装中有$ _SERVER ['SCRIPT_URI']而有些却没有


1

对于使用IIS的用户,在web.config中添加此行将有所帮助:

<httpProtocol>
    <customHeaders>
        <add name="Strict-Transport-Security" value="max-age=31536000"/>
    </customHeaders>
</httpProtocol>
<rewrite>
    <rules>
        <rule name="HTTP to HTTPS redirect" stopProcessing="true">
              <match url="(.*)" />
              <conditions>
                 <add input="{HTTPS}" pattern="off" ignoreCase="true" />
              </conditions>
              <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
         </rule>
    </rules>
</rewrite>

完整的示例文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Strict-Transport-Security" value="max-age=31536000"/>
             </customHeaders>
        </httpProtocol>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="true">
                      <match url="(.*)" />
                      <conditions>
                         <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                      </conditions>
                      <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
                 </rule>
            </rules>
       </rewrite>
   </system.webServer>
</configuration>

该问题专门询问有关Apache而不是IIS的问题。
Quentin

1
A)其未标记的Apache。在引号之间引用Apache。B)这是一个一般性的问题,与一般的Apache无关。它适用于多个支持PHP的网络服务器
Tschallacka

0

您不应该出于安全原因。特别是在这里使用cookie时。它使您对基于cookie的重播攻击敞开了大门。

无论哪种方式,都应使用Apache控制规则进行调整。

然后,您可以测试是否启用了HTTPS,并在需要时根据需要重定向。

您应该仅使用FORM POST(无获取)重定向到付款页面,并且在没有POST的情况下访问该页面应直接回到其他页面。(这会引起人们的热跳。)

http://joseph.randomnetworks.com/archives/2004/07/22/redirect-to-ssl-using-apaches-htaccess/

是一个很好的起点,很抱歉没有提供更多。但是您确实应该通过SSL推送所有内容。

它具有过度保护的功能,但至少您的担忧更少。


0

也许这可以帮到您,这就是我为我的网站所做的,它的工作原理就像一个魅力:

$protocol = $_SERVER["HTTP_CF_VISITOR"];

if (!strstr($protocol, 'https')){
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
    exit();
}

0

如果您想使用PHP来做到这一点,那么这种方式对我来说真的很好:


<?php

if(!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != "on") {
    header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"], true, 301);
    //Prevent the rest of the script from executing.
    exit;
}
?>

它检查$ _SERVER超全局数组中的HTTPS变量是否等于“ on”。如果变量不等于on。


-1

我已经使用了此脚本,并且该脚本在整个网站上都能正常工作。

if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off"){
    $redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    enter code hereheader('HTTP/1.1 301 Moved Permanently');
    header('Location: ' . $redirect);
    exit();
}

-2
<?php 
// Require https
if ($_SERVER['HTTPS'] != "on") {
    $url = "https://". $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
    header("Location: $url");
    exit;
}
?>

这么简单

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.