Як змусити користувачів отримати доступ до моєї сторінки через 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 для всіх сторінок?
Тахаан

Відповіді:


177

Те, що я робив раніше, в основному схоже на те, що ви написали, але не має жодних твердо кодованих значень:

if ($ _ SERVER ["HTTPS"]! = "on")
{
    заголовок ("Місце: https: //". $ _SERVER ["HTTP_HOST"]. $ _SERVER ["REQUEST_URI"]);
    вихід();
}

15
Ви забули зателефонувати exit (), щоб переконатися, що сценарій закінчується після переадресації. Зазвичай я запускаю це у функцію, яку називають RequSSL (). Я можу це викликати у верхній частині будь-якої сторінки, яку хочу зашифрувати.
Джессі Вайгерт

31
Змініть, якщо потрібно (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] !== "on")виправити повідомлення PHP.
dave1010

Чи не $_SERVER[]змінні / вразливі для втручання користувачі змінні?
Аріан Фауртош

@ArianFaurtosh джерело?
Іван-

3
@ArianFaurtosh деякі витягуються із заголовків клієнтів, як-от HTTP_X_FORWARDED, і ними можна маніпулювати, але інші люблять HTTPSабо SERVER_PORTвстановлюються безпосередньо з веб-сервера і зазвичай мають бути безпечними.
Ман

46

Ви можете зробити це за допомогою директиви та mod_rewrite на Apache:

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

Ви можете зробити Місце розташування розумнішим із часом, використовуючи регулярні вирази, якщо хочете.


6
Куди б ти це поклав? .htaccess файл?

1
Чи REQUEST_URI не містить "рядок запиту" (наприклад? Page = 1 & id = 41 тощо)? Ось що пише в документації на апачі ... Тож якщо я спробую отримати доступ до site.com/index.php?page=1&id=12, мене переспрямують site.com/index.php
Rolf

2
З документації apache: REQUEST_URI Компонент шляху запитуваного URI, наприклад "/index.html". Це, зокрема, виключає рядок запиту, який доступний як власна змінна назва QUERY_STRING. Тому вам потрібно буде додати QUERY_STRING після REQUEST_URI
Рольфа

2
Також потрібно додати флажок [R] після цього, щоб зробити його переадресацією
Рольф

40

Ви повинні змусити клієнта запитувати HTTPS завжди з заголовками суворої безпеки HTTP (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, щоб подальші запити клієнтів повинні бути перенаправлені браузером, якщо це можливо.


Я здивований, що з інших відповідей не входить цей заголовок, це дуже важливо ... якийсь підводний камінь для їх поєднання?
keisar

Ні ... ви точно можете встановити цей заголовок у будь-якому випадку, якщо ви хочете, щоб HTTPS завжди був. Це просто зайве встановити його до і після того, як ви перейдете. Я також змінив свою відповідь вище, щоб більш точно пояснити сумісність.
Jacob Swartwood

1
(Відновлення оригінального коментаря) Я не помітив конкретної вимоги "лише однієї сторінки". HSTS застосовуватиметься до всіх сторінок; моя відповідь технічно неправильна.
Jacob Swartwood

4
FYI, у стандартному розділі 7.2 RFC 6797 написано: "Хост HSTS НЕ повинен включати поле заголовка STS у відповіді HTTP, що передаються через незахищений транспорт". тому не потрібно надсилати його, коли запит є звичайним http, його слід ігнорувати, якщо браузер відповідає стандарту.
Френк Форте

1
@mark, якщо є MITM, і на вашому веб-сайті немає цього заголовка, ви можете дозволити складеному сеансу переходити на http, і люди вводять свої дані, і вони, ймовірно, не помітять, а перенаправлення не допоможе (людина в середина підключиться до сайту через https та представить його як http). Використання цього заголовка примусить HTTPS на стороні клієнта. Це особливо важливо через недавню вразливість безпеки Wi-Fi у WPA2.
Рудігер

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);
}

Спосіб mod_rewrite Apache:

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

Я віддаю перевагу PHP-способу, тому що є випадки, коли я хочу перекрити вимогу до SSL. Наприклад, локальний доступ до API та таких речей, як автоконфігурація Mozilla Thunderbird тощо
Jay

Метод 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.


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 див. У документах-> http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

Деякі складові тут -> Примушуйте SSL / https, використовуючи .htaccess та mod_rewrite
та
отримуючи повну URL-адресу поточна сторінка (PHP),
щоб назвати пару.


2
але тепер я отримую наступне повідомлення про помилку: ERR_TOO_MANY_REDIRECTS. Як це виправити?
Патрос

3

Використовуйте, $_SERVER['HTTPS']щоб сказати, чи це SSL , а якщо ні, то переспрямуйте в потрібне місце.

І пам’ятайте, що на сторінці, що відображає форму, не потрібно подавати через HTTPS, це саме URL-адреса, яка потрібна найбільше.

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


Це правда, що сама форма не повинна бути https, хоча це гарна ідея для більшості людей, які цього не знають. Якщо вони збираються надіслати форму і помітять, що піктограма блокування не існує, вони можуть помилково припустити, що форма є небезпечною.
Graeme Perrow

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 разом із посиланням для надсилання не є суттєвою зміною переваги.


1

Якщо ви використовуєте Apache або щось на зразок LiteSpeed, яке підтримує .htaccess файли, ви можете зробити наступне. Якщо ви ще не маєте. Тепер додайте ці рядки як перші правила перезапису у свій .htaccess:

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

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

Я сподіваюся, що це допомагає.


Це те, що працювало на мене, і те, що я використовую в своїх власних сценаріях на Zend 2-Framework Framework - я не розумію голоси.
Антоніо

Можливо, вас зняли з посади, тому що відповідь практично така ж, як і відповідь від @MatHatrik, яка була опублікована на рік раніше?
Загинув

1

Використання цього НЕ достатньо:

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

Якщо у вас є будь-який вміст http (наприклад, зовнішнє джерело зображень http), браузер виявить можливу загрозу. Тому будьте впевнені, що всі ваші ref та src у вашому коді є https


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
А) його не позначений апаш. Апач вимірюється між цитатами. Б) це загальне питання, яке взагалі не має нічого спільного з апачем.
Застосовується

0

Ви не повинні з міркувань безпеки. Особливо, якщо тут грають куки. Це залишає вас широко відкритими для атак на повторення на основі файлів cookie.

У будь-якому випадку, ви повинні використовувати правила контролю Apache, щоб настроїти його.

Тоді ви можете перевірити, чи HTTPS увімкнено та перенаправити за потребою, де потрібно.

Ви повинні перенаправляти на сторінку оплати лише за допомогою ФОРМУЛЬНОГО ПОШТУ (не отримуйте), а доступ до сторінки без 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;
}
?>

Він перевіряє змінну HTTPS у суперглобальному масиві $ _SERVER, щоб побачити, чи дорівнює вона "увімкнено". Якщо змінна не дорівнює.


-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;
}
?>

Це просто.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.