Автоматический редирект на HTTPS, если браузер его поддерживает

Board index phpBBex 1.x Мастерская

Description: Только готовые решения! Статьи, заметки, моды и другие полезности для phpBBex 1.x и phpBB 3.0.x.
Moderator: Поддержка

Post #1by VEG » 15.11.2020, 17:50

В современном вебе стоит использовать HTTPS, и желательно настроить автоматический редирект на HTTPS, если у пользователя достаточно свежий браузер. Предлагаю следующую конфигурацию для Apache, которую нужно поместить в самое начало файла .htaccess в корне вашего сайта. Требуется Apache 2.4+, а также модули mod_rewrite, mod_headers и mod_setenvif (если приведённый ниже конфиг не работает, проверьте что эти модули включены).

Code: Select all
RewriteEngine On
RewriteBase /

# ----------------------------------------------------------------------------------------------------------------------
# Detect current scheme. REQUEST_SCHEME is not reliable since Apache may be behind Nginx.
# ----------------------------------------------------------------------------------------------------------------------

RewriteRule ^ - [E=REQ_SCHEME:http]
RewriteCond %{HTTPS} ^on$ [NC,OR]
RewriteCond %{HTTP:X-Forwarded-Proto} https [NC,NV]
RewriteRule ^ - [E=REQ_SCHEME:https]

# ----------------------------------------------------------------------------------------------------------------------
# No www. We should do it before we try to set any cookies or any other redirects.
# ----------------------------------------------------------------------------------------------------------------------

RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule ^/?(.*)$ %{ENV:REQ_SCHEME}://%1/$1 [NE,R=301,END]

# ----------------------------------------------------------------------------------------------------------------------
# Force HTTPS if required.
# ----------------------------------------------------------------------------------------------------------------------

# Force HTTPS if Upgrade-Insecure-Requests is supported. Let's Encrypt is definitely supported in this case.
# Let's Encrypt is supported: Firefox 2+, Chrome 1+, Windows XP SP3+, Android OS v2.3.6+.
# Upgrade-Insecure-Requests: IE18+ (2018), Firefox 48+ (2016), Chrome 44+ (2015), Safari 10.1+ (2017).
# Strict-Transport-Security: IE11+ (2015), Firefox 4+ (2011), Chrome 4+ (2010), Safari 7+ (2013), Android 4.4+ (2013).

RewriteRule ^ - [E=USE_SCHEME:%{ENV:REQ_SCHEME}]

# Use HTTPS if UIR is supported and forcessl cookie is not 0.
RewriteCond %{HTTP:Upgrade-Insecure-Requests}  ^1$
RewriteCond %{HTTP_COOKIE} !(?:^|;)\s*forcessl=0\s*(?:;|$)
RewriteRule ^ - [E=USE_SCHEME:https]

# Use HTTPS if forcessl cookie is 1.
RewriteCond %{HTTP_COOKIE}  (?:^|;)\s*forcessl=1\s*(?:;|$)
RewriteRule ^ - [E=USE_SCHEME:https]

# Set or remove the forcessl cookie depending on the forcessl URL parameter.
RewriteCond %{QUERY_STRING} (?:^|&)forcessl=-(?:&|$)
RewriteRule ^ - [E=SET_FORCESSL_COOKIE:-,E=USE_SCHEME:http]
RewriteCond %{QUERY_STRING} (?:^|&)forcessl=0(?:&|$)
RewriteRule ^ - [E=SET_FORCESSL_COOKIE:0,E=USE_SCHEME:http]
RewriteCond %{QUERY_STRING} (?:^|&)forcessl=1(?:&|$)
RewriteRule ^ - [E=SET_FORCESSL_COOKIE:1,E=USE_SCHEME:https]

# Set forcessl=1 if Upgrade-Insecure-Requests isn't supported, forcessl cookie isn't set, and current scheme is HTTPS.
# RewriteCond %{ENV:REQ_SCHEME} ^https$
# RewriteCond %{HTTP:Upgrade-Insecure-Requests} !^1$
# RewriteCond %{HTTP_COOKIE} !(?:^|;)\s*forcessl=[-01]\s*(?:;|$)
# RewriteCond %{ENV:SET_FORCESSL_COOKIE} !^[-01]$
# RewriteRule ^ - [E=SET_FORCESSL_COOKIE:1]

# Decide if we want to enable STS.
RewriteCond %{ENV:REQ_SCHEME} ^https$
RewriteRule ^ - [E=SET_FORCESTS_HEADER:0]
RewriteCond %{ENV:REQ_SCHEME} ^https$
RewriteCond %{ENV:USE_SCHEME} ^https$
RewriteCond %{HTTP:Upgrade-Insecure-Requests}  ^1$
RewriteCond %{HTTP_COOKIE} !(?:^|;)\s*forcessl=0\s*(?:;|$)
RewriteCond %{ENV:SET_FORCESSL_COOKIE} !^[-0]$
RewriteRule ^ - [E=SET_FORCESTS_HEADER:1]

# Try to fix stupid adding of the "REDIRECT_" prefix to environment variable names on URL rewrite.
SetEnvIf REDIRECT_USE_SCHEME    (.+) USE_SCHEME=$1
SetEnvIf REDIRECT_REQ_SCHEME    (.+) REQ_SCHEME=$1
SetEnvIf REDIRECT_SET_FORCESTS_HEADER (.+) SET_FORCESTS_HEADER=$1
SetEnvIf REDIRECT_SET_FORCESSL_COOKIE (.+) SET_FORCESSL_COOKIE=$1

# Send cookies in modern format with max-age (IE8+). In IE6-IE7 they will be stored until the browser is closed.
# According to RFC 6265, "host-only" cookie (which won't be sent to subdomains) shouldn't have "domain=" attribute.
Header always add Set-Cookie "forcessl=; path=/; max-age=-1"            "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '-'"
Header always add Set-Cookie "forcessl=0; path=/; max-age=126230400"    "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '0'"
Header always add Set-Cookie "forcessl=1; path=/; max-age=126230400"    "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '1'"

# Set the STS and UIR headers if required.
Header always set Strict-Transport-Security "max-age=2592000"           "expr= '%{ENV:SET_FORCESTS_HEADER}' == '1'"
Header always set Content-Security-Policy "upgrade-insecure-requests"   "expr= '%{ENV:SET_FORCESTS_HEADER}' == '1'"
Header always set Strict-Transport-Security "max-age=0"                 "expr= '%{ENV:SET_FORCESTS_HEADER}' == '0'"

# Canonical prefix.
RewriteRule ^ - [E=URI_PREFIX:%{ENV:USE_SCHEME}://%{HTTP_HOST}]
SetEnvIf REDIRECT_URI_PREFIX (.+) URI_PREFIX=$1

# Remove the forcessl URL parameter.
RewriteCond %{QUERY_STRING} ^(.*&|)forcessl=[-01](?:&(.*)|)$
RewriteRule ^/?(.*)$ %{ENV:URI_PREFIX}/$1?%1%2 [NE,R=302,END]

# Redirect to HTTPS or HTTP if desired scheme is different from used in this request.
RewriteCond %{ENV:REQ_SCHEME}:%{ENV:USE_SCHEME} !^(.+):\1$
RewriteRule ^/?(.*)$ %{ENV:URI_PREFIX}/$1 [NE,R=302,END]

# ----------------------------------------------------------------------------------------------------------------------

Фишки этого конфига:
  • Автоматическое удаление www из хоста (если нужно, можете заменить на другой вариант установки каноничного хоста).
  • Если сайт открыт через HTTPS, то автоматически настраивается Upgrade-Insecure-Requests (все ресурсы, ссылки на которые указаны через http, будут всё равно загружены через https) и Strict-Transport-Security (браузер всегда будет открывать сайт по HTTPS).
  • Если браузер слишком старый и не поддерживает Upgrade-Insecure-Requests, то редирект на HTTPS не производится, сайт продолжает работать по HTTP.
  • Пользователь может установить принудительный редирект на HTTPS (forcessl=1), принудительно отключить редирект (forcessl=0), или вернуть автоматический режим (forcessl=-), передав любой странице по любому протоколу параметр forcessl (выбор запоминается в cookies).

Если вам надо настроить редирект с разных хостов на один каноничный — делайте это на месте удаления www. Если добавляете ещё какие-то редиректы уже внутри сайта, то лучше их размещать после приведённого выше кода. В редиректах можете использовать переменную %{ENV:URI_PREFIX} вместо явного указания протокола и хоста (он содержит строку вида https://example.com), или переменную %{ENV:USE_SCHEME} в качестве предпочитаемого протокола (там будет либо http, либо https, в зависимости от свежести браузера пользователя).
С наилучшими пожеланиями, Евгений
VEG M Online
Topic author, Администратор
Avatar
Age: 33
Location: Минск, Беларусь
Reputation: 1600
With us: 8 years 7 months

Post #2by Sumanai » 17.11.2020, 19:41

VEG wrote:Apache
А ты старовер ))
Использование поиска продлевает жизнь.
Это форум поддержки форка phpBBex. Поддержка по phpBB осуществляется в других местах.
Sumanai M
Гуру
Avatar
Reputation: 1676
With us: 7 years 10 months

Post #3by VEG » 17.11.2020, 21:58

Работает — не трожь =)
С наилучшими пожеланиями, Евгений
VEG M Online
Topic author, Администратор
Avatar
Age: 33
Location: Минск, Беларусь
Reputation: 1600
With us: 8 years 7 months

Post #4by VEG » 19.11.2020, 18:05

Недавно было в новостях, что Let's Encrypt переходит на собственный корневой сертификат "ISRG Root X1" (действителен до 2035 года), поэтому их сертификаты перестанут приниматься на необновлённых системах, которые ничего не знают про "ISRG Root X1". Под ударом Android до версии 7.1.1, необновлённые Windows до 2018 года. Обновил приведённый выше код с учётом этого, чтобы в старом ПО отключить автоматический редирект на HTTPS по чёрному списку User-Agent устаревших ОС и браузеров.

Code: Select all
RewriteEngine On
RewriteBase /

# ----------------------------------------------------------------------------------------------------------------------
# Detect current scheme. REQUEST_SCHEME is not reliable since Apache may be behind Nginx.
# ----------------------------------------------------------------------------------------------------------------------

RewriteRule ^ - [E=REQ_SCHEME:http]
RewriteCond %{HTTPS} ^on$ [NC,OR]
RewriteCond %{HTTP:X-Forwarded-Proto} https [NC,NV]
RewriteRule ^ - [E=REQ_SCHEME:https]

# ----------------------------------------------------------------------------------------------------------------------
# No www. We should do it before we try to set any cookies or any other redirects.
# ----------------------------------------------------------------------------------------------------------------------

RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule ^/?(.*)$ %{ENV:REQ_SCHEME}://%1/$1 [NE,R=301,END]

# ----------------------------------------------------------------------------------------------------------------------
# Force HTTPS if required.
# ----------------------------------------------------------------------------------------------------------------------

# Let's Encrypt "DST Root CA X3" 2021-: Firefox 2+, Windows XP SP3+, Android 2.3.6+, iOS 3.1+, Safari 4+, MacOS 10.4+.
# Let's Encrypt "ISRG Root X1"   2021+: Firefox 50+, Windows 7+ (2018/07/31), Android 7.1.1+ (2017), iOS 10+ (2017).
# Windows XP: Firefox 52-, Chrome 49-. Chrome 70 was released 2018/10/16 (older version may be on too old Windows).
# Upgrade-Insecure-Requests: IE18+ (2018), Firefox 48+ (2016), Chrome 44+ (2015), Safari 10.1+ (2017).
# Strict-Transport-Security: IE11+ (2015), Firefox 4+ (2011), Chrome 4+ (2010), Safari 7+ (2013), Android 4.4+ (2013).

# Allow UIR if Upgrade-Insecure-Requests is in the request headers.
RewriteRule ^ - [E=PERMIT_UIR:0]
RewriteCond %{HTTP:Upgrade-Insecure-Requests} ^1$
RewriteRule ^ - [E=PERMIT_UIR:1]

# Allow STS if UIR is allowed, and browser and OS are not too old (and probably support Let's Encrypt).
RewriteRule ^ - [E=PERMIT_STS:0]
RewriteCond %{ENV:PERMIT_UIR} ^1$
RewriteCond %{HTTP_USER_AGENT} !Android\s([1-6]\.|7\.0|7\.1\.0)
RewriteCond %{HTTP_USER_AGENT} !Windows\sNT\s(5\.|6\.0)
RewriteCond %{HTTP_USER_AGENT} !Firefox\/[1-4]?[0-9]\.
RewriteCond %{HTTP_USER_AGENT} !Windows\sNT.*Chrome\/[1-6]?[0-9]\.
RewriteRule ^ - [E=PERMIT_STS:1]

# Force HTTPS if STS is allowed and forcessl cookie is not 0.
RewriteRule ^ - [E=USE_SCHEME:%{ENV:REQ_SCHEME}]
RewriteCond %{ENV:PERMIT_STS} ^1$
RewriteCond %{HTTP_COOKIE} !(?:^|;)\s*forcessl=0\s*(?:;|$)
RewriteRule ^ - [E=USE_SCHEME:https]

# Use HTTPS if forcessl cookie is 1.
RewriteCond %{HTTP_COOKIE}  (?:^|;)\s*forcessl=1\s*(?:;|$)
RewriteRule ^ - [E=USE_SCHEME:https]

# Set or remove the forcessl cookie depending on the forcessl URL parameter.
RewriteCond %{QUERY_STRING} (?:^|&)forcessl=-(?:&|$)
RewriteRule ^ - [E=SET_FORCESSL_COOKIE:-,E=USE_SCHEME:http]
RewriteCond %{QUERY_STRING} (?:^|&)forcessl=0(?:&|$)
RewriteRule ^ - [E=SET_FORCESSL_COOKIE:0,E=USE_SCHEME:http]
RewriteCond %{QUERY_STRING} (?:^|&)forcessl=1(?:&|$)
RewriteRule ^ - [E=SET_FORCESSL_COOKIE:1,E=USE_SCHEME:https]

# Set forcessl=1 if STS isn't allowed, forcessl cookie isn't set, and current scheme is HTTPS.
# RewriteCond %{ENV:REQ_SCHEME} ^https$
# RewriteCond %{ENV:PERMIT_STS} !^1$
# RewriteCond %{HTTP_COOKIE} !(?:^|;)\s*forcessl=[-01]\s*(?:;|$)
# RewriteCond %{ENV:SET_FORCESSL_COOKIE} !^[-01]$
# RewriteRule ^ - [E=SET_FORCESSL_COOKIE:1]

# Canonical prefix.
RewriteRule ^ - [E=URI_PREFIX:%{ENV:USE_SCHEME}://%{HTTP_HOST}]

# Decide if we want to send STS and UIR headers. Never send them when current request is HTTP.
RewriteCond %{ENV:REQ_SCHEME} ^https$
RewriteRule ^ - [E=SET_FORCESTS_HEADER:0,E=SET_FORCEUIR_HEADER:0]
RewriteCond %{ENV:REQ_SCHEME} ^https$
RewriteCond %{ENV:USE_SCHEME} ^https$
RewriteRule ^ - [E=SET_FORCESTS_HEADER:%{ENV:PERMIT_STS},E=SET_FORCEUIR_HEADER:%{ENV:PERMIT_UIR}]

# Try to fix stupid adding of the "REDIRECT_" prefix to environment variable names on URL rewrite.
SetEnvIf REDIRECT_PERMIT_UIR            (.+) PERMIT_UIR=$1
SetEnvIf REDIRECT_PERMIT_STS            (.+) PERMIT_STS=$1
SetEnvIf REDIRECT_REQ_SCHEME            (.+) REQ_SCHEME=$1
SetEnvIf REDIRECT_USE_SCHEME            (.+) USE_SCHEME=$1
SetEnvIf REDIRECT_URI_PREFIX            (.+) URI_PREFIX=$1
SetEnvIf REDIRECT_SET_FORCESSL_COOKIE   (.+) SET_FORCESSL_COOKIE=$1
SetEnvIf REDIRECT_SET_FORCESTS_HEADER   (.+) SET_FORCESTS_HEADER=$1
SetEnvIf REDIRECT_SET_FORCEUIR_HEADER   (.+) SET_FORCEUIR_HEADER=$1

# Send cookies in modern format with max-age (IE8+). In IE6-IE7 they will be stored until the browser is closed.
# According to RFC 6265, "host-only" cookie (which won't be sent to subdomains) shouldn't have "domain=" attribute.
Header always add Set-Cookie "forcessl=; path=/; max-age=-1"            "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '-'"
Header always add Set-Cookie "forcessl=0; path=/; max-age=126230400"    "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '0'"
Header always add Set-Cookie "forcessl=1; path=/; max-age=126230400"    "expr= '%{ENV:SET_FORCESSL_COOKIE}' == '1'"

# Send the STS and UIR headers if required. 2592000 seconds = 30 days.
Header always set Strict-Transport-Security "max-age=2592000"           "expr= '%{ENV:SET_FORCESTS_HEADER}' == '1'"
Header always set Strict-Transport-Security "max-age=0"                 "expr= '%{ENV:SET_FORCESTS_HEADER}' == '0'"
Header always set Content-Security-Policy "upgrade-insecure-requests"   "expr= '%{ENV:SET_FORCEUIR_HEADER}' == '1'"

# Remove the forcessl URL parameter.
RewriteCond %{QUERY_STRING} ^(.*&|)forcessl=[-01](?:&(.*)|)$
RewriteRule ^/?(.*)$ %{ENV:URI_PREFIX}/$1?%1%2 [NE,R=302,END]

# Redirect to HTTPS or HTTP if desired scheme is different from used in this request.
RewriteCond %{ENV:REQ_SCHEME}:%{ENV:USE_SCHEME} !^(.+):\1$
RewriteRule ^/?(.*)$ %{ENV:URI_PREFIX}/$1 [NE,R=302,END]

# ----------------------------------------------------------------------------------------------------------------------

Firefox использует собственное хранилище корневых сертификатов, поэтому в Firefox 50+ даже на необновлённой версии Windows всё будет работать. Такую же фичу хотят сделать в Chrome. Когда это будет сделано, я расширю список версий Chrome где отключен автоматический редирект до той, где начнёт использоваться собственное хранилище, где будет и "ISRG Root X1".
С наилучшими пожеланиями, Евгений
VEG M Online
Topic author, Администратор
Avatar
Age: 33
Location: Минск, Беларусь
Reputation: 1600
With us: 8 years 7 months


Return to Мастерская



Who is online (over the past 10 minutes)

Users browsing this forum: 1 guest