Как заставить пользователей обращаться к моей странице по HTTPS вместо HTTP?

137

У меня есть только одна страница, к которой я хочу принудительно обращаться как к странице HTTPS (PHP на Apache). Как мне сделать это, не требуя HTTPS для всего каталога? Или, если вы отправляете форму на страницу HTTPS со страницы HTTP, отправляет ли она ее по 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 для всех страниц?
The Tahaan

Ответы:

178

То, как я делал это раньше, в основном похоже на то, что вы написали, но не имеет жестко запрограммированных значений:

if ($ _ SERVER ["HTTPS"]! = "on")
{
    заголовок ("Местоположение: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    Выход();
}
Адам Розенфилд
источник
15
Вы забыли вызвать exit (), чтобы гарантировать завершение работы сценария после перенаправления. Я обычно заключаю это в функцию под названием requireSSL (). Я могу это назвать вверху любой страницы, которую я хочу зашифровать.
Джесси Вейгерт,
31
Измените if, (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")чтобы исправить уведомления PHP.
dave1010
Разве $_SERVER[]переменные не изменяются / не уязвимы для вмешательства пользователей?
Ариан Фауртош
Источник @ArianFaurtosh?
Джон
3
@ArianFaurtosh, некоторые из них извлекаются из заголовков клиентов, например HTTP_X_FORWARDED, и ими можно управлять, но другие, например, HTTPSили SERVER_PORTустанавливаются непосредственно с веб-сервера и обычно должны быть безопасными.
Mahn
46

Вы можете сделать это с помощью директивы и mod_rewrite на Apache:

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

Вы можете со временем сделать Location умнее, используя регулярные выражения, если хотите.

thebigjc
источник
6
Куда бы вы это положили? .htaccess файл?
1
Разве REQUEST_URI не включает «строку запроса» (например,? Page = 1 & id = 41 и т. Д.)? Это то, что говорится в документации apache ... Итак, если я попытаюсь получить доступ к site.com/index.php?page=1&id=12, я буду перенаправлен на site.com/index.php
Рольф
2
Из документации apache: REQUEST_URI Компонент пути запрошенного URI, например "/index.html". Это, в частности, исключает строку запроса, которая доступна как собственная переменная с именем QUERY_STRING. Итак, вам нужно добавить QUERY_STRING после REQUEST_URI
Рольф
2
Вам также необходимо добавить флаг [R] после этого, чтобы сделать перенаправление
Рольф
40

Вы должны заставить клиента запрашивать HTTPS всегда с заголовками HTTP Strict Transport Security (HSTS):

// 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, а затем устанавливает заголовок HSTS так, чтобы дальнейшие клиентские запросы по возможности перенаправлялись браузером.

оборота Jacob Swartwood
источник
Я удивлен, что ни один из других ответов не включает этот заголовок, это довольно важно ... есть ли ловушка для объединения двух из них?
keisar
Нет ... вы все равно можете установить этот заголовок, если хотите всегда использовать HTTPS. Просто излишне устанавливать его до и после перенаправления. Я также изменил свой ответ выше, чтобы более точно объяснить совместимость.
Джейкоб Свартвуд
1
(Редактирование исходного комментария) Я не заметил особого требования «всего одна страница». HSTS будет применяться ко всем страницам; мой ответ технически неверен.
Джейкоб Свартвуд
4
К вашему сведению, в стандартном разделе 7.2 RFC 6797 говорится: «Хост HSTS НЕ ДОЛЖЕН включать поле заголовка STS в HTTP-ответы, передаваемые по незащищенному транспорту». поэтому нет необходимости отправлять его, если запрос является обычным http, его следует игнорировать, если браузер соответствует стандарту.
Франк Форте
1
@mark, если существует MITM и на вашем веб-сайте нет этого заголовка, вы можете разрешить входящему в состав сеансу перейти на http, и люди будут вводить свои данные, и они, вероятно, не заметят, и перенаправление не поможет (человек в средний будет подключаться к сайту через https и представлять его как http). Использование этого заголовка приведет к принудительному использованию HTTPS на стороне клиента. Это особенно важно из-за недавней уязвимости безопасности WPA2 WiFi.
Рудигер
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;
    }
}
оборота syvex
источник
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 и т. Д.
Джей,
Метод PHP отлично работает для меня, очень рекомендуется.
Moxet
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.

Itsazzad
источник
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 (Одинаковая сессия, разные значения)

Так что все, что я говорю, это не соглашайтесь на одно или другое, когда ответ заключается в комбинации.

Для получения дополнительной информации о перезаписи доступа https см. Docs-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Некоторые стеки здесь -> Принудительное использование SSL / https с использованием .htaccess и mod_rewrite
и
получение полного URL текущая страница (PHP),
чтобы назвать пару.

JSG
источник
2
но теперь я получаю следующее сообщение об ошибке: ERR_TOO_MANY_REDIRECTS. Как это исправить?
Pathros
3

Используйте, $_SERVER['HTTPS']чтобы определить, является ли это SSL , и перенаправить в нужное место, если нет.

И помните, что страницу, на которой отображается форма, не нужно загружать через HTTPS, это URL-адрес обратной отправки, который больше всего в этом нуждается.

Изменить : да, как указано ниже, лучше всего иметь весь процесс в HTTPS. Это намного обнадеживает - я указывал, что пост - самая важная часть. Кроме того, вам необходимо позаботиться о том, чтобы все файлы cookie были безопасными, поэтому они будут отправляться только через SSL. Решение mod_rewrite также очень изящное, я использовал его для защиты множества приложений на моем собственном веб-сайте.

DGM
источник
Это правда, что сама форма не обязательно должна быть https, хотя это хорошая идея для большинства людей, которые этого не знают. Если они собираются отправить форму и заметят, что значка замка нет, они могут ошибочно предположить, что форма небезопасна.
Грэм Перроу,
1
@Graeme: кроме того, никто не может быть уверен, что форма когда-либо будет отправлена ​​через https. Вся форма (отображаемая через http) может быть подделкой, отправленной на неизвестный сайт или сайт с открытым текстом http. Https - это не только шифрование, но и проверка подлинности сервера.
Олаф Кок,
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 вместе со ссылкой для отправки - не такое уж серьезное изменение для преимущества.

JBB
источник
1

Если вы используете Apache или что-то вроде LiteSpeed, которое поддерживает файлы .htaccess, вы можете сделать следующее. Если у вас еще нет файла .htaccess, вам следует создать новый файл .htaccess в корневом каталоге (обычно там, где находится ваш index.php). Теперь добавьте эти строки в качестве первых правил перезаписи в свой .htaccess:

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

Вам понадобится только один раз инструкция "RewriteEngine On" в вашем .htaccess для всех правил перезаписи, поэтому, если она у вас уже есть, просто скопируйте вторую и третью строку.

Надеюсь, это поможет.

Антонио
источник
Это то, что у меня сработало, и то, что я использую в своих собственных скриптах на платформе, подобной Zend 2 - я не понимаю, что такое отрицательное мнение.
Антонио
Может быть , вы получили downvoted , потому что ответ практически такой же , как этот от @MatHatrik , которая была размещена более чем на год раньше?
Уилт
1

Недостаточно использовать это:

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

Если у вас есть какой-либо http-контент (например, внешний источник http-изображения), браузер обнаружит возможную угрозу. Поэтому убедитесь, что все ваши ref и src внутри вашего кода https

веб-мастер bourax
источник
1

Я прошел через множество решений с проверкой статуса $ _SERVER [HTTPS], но кажется, что это ненадежно, потому что иногда он не устанавливается или не включается, выключается и т. Д., Вызывая перенаправление скрипта во внутренний цикл.

Вот самое надежное решение, если ваш сервер поддерживает $ _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.
Квентин
1
А) это немаркированный apache. Apache указывается в кавычках. Б) это общий вопрос, который не имеет ничего общего с apache в целом. Это применимо к нескольким веб-серверам, поддерживающим php
Tschallacka
1

Если вы хотите использовать для этого 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;
}
?>

Он проверяет переменную HTTPS в суперглобальном массиве $ _SERVER, чтобы убедиться, что она равна «on». Если переменная не равна on.

оруженосец
источник
0

Не следует из соображений безопасности. Особенно, если здесь используются куки. Это оставляет вас широко открытыми для атак с использованием файлов 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();
}
Héouais Mongars
источник
-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;
}
?>

Это просто.

Орфографии
источник