Принудительное использование SSL/https с помощью .htaccess и mod_rewrite

Как я могу заставить SSL/https использовать .htaccess и mod_rewrite page specific в PHP.

 

Ответ 1

Для Apache вы можете использовать mod_ssl для принудительного использования SSL с помощью директивы SSLRequireSSL. Эта директива запрещает доступ, если для текущего соединения не включен HTTP по SSL (т. е. HTTPS). Это очень удобно внутри виртуального хоста с поддержкой SSL или в каталогах для защиты от ошибок конфигурации, которые открывают то, что должно быть защищено. Когда эта директива присутствует, все запросы, не использующие SSL, отклоняются. Однако это не приведет к перенаправлению на https. Для перенаправления попробуйте следующее с помощью mod_rewrite в файле .htaccess

RewriteEngine On

RewriteCond % { HTTPS } !=on

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

 Вы также можете решить эту проблему PHP в случае, если ваш провайдер отключил .htaccess (что маловероятно, поскольку вы просили об этом):

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

     }

}

 

Ответ 2

Я нашел решение mod_rewrite, которое хорошо работает как для проксированных, так и для непроксированных серверов. Если вы используете CloudFlare, AWS Elastic Load Balancing, Heroku, OpenShift или любое другое решение Cloud/PaaS и испытываете зацикливание перенаправления при обычном перенаправлении HTTPS, попробуйте использовать следующий фрагмент.

RewriteEngine On

# Если мы получаем перенаправленный http-запрос от прокси-сервера...

RewriteCond % { HTTP:X-Forwarded-Proto } =http [OR]

# ...или обычный старый http запрос непосредственно от клиента

RewriteCond % { HTTP:X-Forwarded-Proto } =""

RewriteCond % { HTTPS } !=on

# Перенаправление на https-версию

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

 

Ответ 3

Решение PHP

Я заметил, что в вашем вопросе упоминается специфичность страницы для принудительного HTTPS/SSL-соединения.

function forceHTTPS() {

  $httpsURL = 'https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];

  if( count( $_POST )>0 )

    die( 'Доступ к странице должен осуществляться по HTTPS, но здесь отправлено POST-представление. Настройте форму так, чтобы она указывала на '.$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, вы можете потребовать централизованный файл, содержащий эту (и любые другие) пользовательские функции, а затем просто запустить функцию forceHTTPS().

Решение HTACCESS / mod_rewrite

Я лично не реализовывал подобное решение (я склонялся к использованию PHP-решения, как описано выше, из-за его простоты), но следующее может быть, по крайней мере, хорошим началом.

RewriteEngine on

# Проверка представления POST

RewriteCond % { REQUEST_METHOD } !^POST$

# Принудительное использование HTTPS

RewriteCond % { HTTPS } !=on [OR]

RewriteCond % { SERVER_PORT } 80

# Страницы для подачи заявки

RewriteCond % { REQUEST_URI } ^something_secure [OR]

RewriteCond % { REQUEST_URI } ^something_else_secure

RewriteRule .* https://% { SERVER_NAME } % { REQUEST_URI } [R=301,L]

# Принудительный HTTP

RewriteCond % { HTTPS } =on [OR]

RewriteCond % { SERVER_PORT } 443

# Страницы для подачи заявки

RewriteCond % { REQUEST_URI } ^что-то_другое_публичное

RewriteRule .* http://% { SERVER_NAME } % { REQUEST_URI } [R=301,L]

 

Ответ 4

Решение на основе 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 } была добавлена в mod-rewrite начиная с версии 2.4.

 

Ответ 5

Я хотел бы отметить, что Apache имеет наихудшие правила наследования при использовании нескольких файлов .htaccess в глубине каталога. Два основных подводных камня:

  1. По умолчанию будут выполняться только правила, содержащиеся в самом глубоком файле .htaccess. Вы должны указать директиву RewriteOptions InheritDownBefore (или аналогичную), чтобы изменить это. 

  2. Шаблон применяется к пути к файлу относительно подкаталога, а не верхнего каталога, содержащего файл .htaccess с заданным правилом. 

Это означает, что предложенное глобальное решение на Apache Wiki не работает, если вы используете любые другие файлы .htaccess в подкаталогах. Я написал модифицированную версию, которая работает:

RewriteEngine On

# Это позволит включить возможности Rewrite

RewriteOptions InheritDownBefore

# Это предотвращает переопределение правила файлами .htaccess в подкаталогах.

RewriteCond % { HTTPS } !=on

# Здесь проверяется, что соединение не является HTTPS.

RewriteRule ^ https://% { SERVER_NAME } % { REQUEST_URI } [QSA,R,L]

# Это правило перенаправит пользователей с их первоначального местоположения на то же место, но с использованием HTTPS.

# то есть  http://www.example.com/foo/ to https://www.example.com/foo/