Переход сайта на HTTPS сам по себе еще не означает, что пользователь никогда не обратится к нему по обычному HTTP. Старые ссылки, ручной ввод адреса, внешние ресурсы и сохраненные закладки могут по-прежнему вести на http://.
Обычно сервер решает эту проблему редиректом:
http://example.com/ - 301 https://example.com/
Но здесь остается небольшой, принципиально важный промежуток: первый запрос браузер все равно отправляет по HTTP. Именно эту проблему решает HSTS — HTTP Strict Transport Security.
HSTS позволяет сайту сообщить браузеру: этот домен необходимо открывать исключительно через HTTPS. После получения такой политики браузер начинает самостоятельно заменять HTTP на HTTPS еще до отправки запроса серверу.
Что такое HSTS
HSTS — механизм веб-безопасности, стандартизированный в RFC 6797. Сервер передает браузеру специальный HTTP-заголовок:
Strict-Transport-Security: max-age=31536000
Получив его через защищенное HTTPS-соединение, браузер запоминает правило для домена.
После этого обращение пользователя к:
http://example.com/page
может быть преобразовано браузером непосредственно в:
https://example.com/page
То есть сначала идти на HTTP-версию сайта и ждать серверного 301 уже не требуется.
Это принципиальное отличие HSTS от обычного HTTP - HTTPS редиректа.
Как работает HSTS
Упрощенно схема выглядит следующим образом.
При первом посещении сайта пользователь может обратиться по HTTP:
http://example.com
Сервер перенаправляет его:
301 → https://example.com
После перехода на HTTPS сервер возвращает:
Strict-Transport-Security: max-age=31536000
Браузер запоминает HSTS-политику. Если позже пользователь снова вводит:
http://example.com
браузер уже знает, что для домена разрешен только HTTPS, поэтому самостоятельно обращается к защищенной версии сайта.
Кроме того, для домена с действующей HSTS-политикой браузер значительно строже относится к ошибкам TLS-сертификата и не должен позволять пользователю просто проигнорировать предупреждение и продолжить работу через небезопасное соединение.
Зачем нужен HSTS, если уже настроен 301-редирект
На первый взгляд механизм действительно кажется избыточным. Если весь HTTP-трафик перенаправляется на HTTPS, зачем нужен еще один заголовок? Проблема заключается именно в первом HTTP-запросе. При обычной схеме:
пользователь
↓
HTTP
↓
сервер
↓
301
↓
HTTPS
браузер должен сначала обратиться к серверу через незашифрованное соединение. HSTS изменяет эту схему:
пользователь
↓
браузер знает HSTS
↓
HTTPS
↓
сервер
HTTP-запрос вообще не выполняется. Механизм предназначен в том числе для защиты от атак, связанных с попыткой принудительно оставить пользователя на незашифрованной версии сайта.
Директива max-age
Основным параметром HSTS является max-age:
Strict-Transport-Security: max-age=31536000
Значение задается в секундах и определяет, как долго браузер должен считать домен HSTS-хостом. Например:
31536000 секунд = примерно 1 год
Каждый новый корректный ответ сайта с HSTS может обновлять этот срок. Значение:
Strict-Transport-Security: max-age=0
наоборот, сообщает браузеру, что сохраненную HSTS-политику для этого хоста необходимо удалить. Важно учитывать это при настройке: большое значение max-age фактически означает обязательство продолжать нормально обслуживать сайт по HTTPS в течение указанного периода. Поэтому экспериментировать сразу с очень большим значением на инфраструктуре, в стабильности которой нет уверенности, не лучшая идея.
includeSubDomains
Следующий вариант:
Strict-Transport-Security: max-age=31536000; includeSubDomains
распространяет политику не только на основной хост, но и на его поддомены. Это усиливает защиту, но одновременно требует осторожности. Предположим, существуют:
example.com
www.example.com
old.example.com
api.example.com
Если для example.com включить includeSubDomains, каждый из соответствующих поддоменов должен быть готов нормально работать через HTTPS.
Старый технический поддомен, внутренний сервис или забытый лендинг без корректного HTTPS после этого могут стать недоступны пользователям, браузеры которых уже получили HSTS-политику.
Поэтому includeSubDomains следует включать после проверки инфраструктуры, а не просто потому, что эта директива выглядит более надежной.
HSTS Preload
У обычного HSTS существует фундаментальное ограничение. Чтобы узнать о политике сайта, браузер сначала должен хотя бы один раз получить:
Strict-Transport-Security
через HTTPS.
Следовательно, для совершенно нового пользователя первое обращение по HTTP все еще потенциально возможно. Для решения этой проблемы существует механизм HSTS Preload. Некоторые браузеры поставляются со списком доменов, для которых HTTPS требуется заранее. Браузеру не нужно сначала посещать сайт и получать от него HSTS — информация уже находится в preload-списке.
Типичная конфигурация выглядит так:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Для включения домена в preload-лист действуют дополнительные требования. В частности, используется includeSubDomains, а max-age должен составлять не менее одного года.
Однако подключать preload без предварительного анализа особенно рискованно: политика распространяется гораздо жестче, а быстро отменить последствия неправильной настройки значительно сложнее.
Почему HSTS передается только через HTTPS
Есть еще одна важная особенность. Заголовок:
Strict-Transport-Security
имеет смысл только в ответе, полученном по HTTPS.
Если сервер возвращает его через обычный HTTP, браузер должен игнорировать такой заголовок.
Это логично: если бы HSTS-политику можно было устанавливать через незащищенное соединение, злоумышленник, способный вмешаться в HTTP-трафик, смог бы манипулировать самой политикой безопасности. Поэтому правильная схема обычно выглядит примерно так:
HTTP
↓
301/308
↓
HTTPS
↓
Strict-Transport-Security
Примеры HSTS
Минимальная конфигурация:
Strict-Transport-Security: max-age=31536000
Политика сроком на год с распространением на поддомены:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Вариант для инфраструктуры, подготовленной к HSTS Preload:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Последний вариант не стоит механически копировать на любой сайт. Сначала необходимо убедиться, что основной домен и требуемые поддомены стабильно работают по HTTPS.
Как проверить наличие HSTS
Для одной страницы проще всего посмотреть HTTP-заголовки ответа через инструменты разработчика браузера или выполнить запрос через консоль.
Например:
curl -I https://example.com/
В ответе нужно найти:
Strict-Transport-Security: ...
Но для одного сайта этого достаточно, а для десятков или сотен URL ручная проверка быстро превращается в рутину. Для таких задач я сделал небольшой скрипт hsts-etag-checker. Он предназначен для массовой проверки наличия HTTP-заголовков Strict-Transport-Security и ETag у списка URL.
Массовая проверка HSTS с помощью hsts-etag-checker
Логика работы максимально простая.
В файл:
urls.txt
помещаются адреса, которые необходимо проверить:
https://example.com
https://example.org
example.net
По одному URL на строку. Если схема не указана, скрипт автоматически добавляет:
https://
Пустые строки и строки-комментарии, начинающиеся с #, пропускаются.
После установки зависимостей:
pip install -r requirements.txt
запускается:
python check.py
Результат сохраняется в:
out.csv
Что находится в отчете
Для каждого URL выводятся четыре основных поля:
url
status
hsts
etag
Например:
url,status,hsts,etag
https://example.com,200,yes,yes
https://example.org,200,no,no
status показывает HTTP-код ответа либо информацию об ошибке.
hsts принимает значения:
yes
no
и показывает наличие заголовка Strict-Transport-Security.
Аналогичным образом etag показывает наличие заголовка ETag. Порядок строк в итоговом CSV сохраняется таким же, как во входном файле.
Зачем одновременно проверять ETag
ETag относится уже к другой задаче.
Заголовок:
ETag
используется в механизме HTTP-кэширования и помогает клиенту определить, изменилась ли версия ресурса. Поэтому HSTS и ETag технически не связаны между собой напрямую. В инструменте они объединены скорее практически: во время технического аудита можно одним проходом получить информацию сразу о нескольких HTTP-заголовках. Основной сценарий в контексте этой статьи — именно массовая проверка HSTS.
Параллельная проверка URL
При большом количестве адресов последовательное выполнение HTTP-запросов может занимать заметное время. Поэтому в скрипте используется параллельная обработка. Количество потоков задается параметром:
MAX_WORKERS
По умолчанию используется:
20
Также можно изменить таймаут запроса:
TIMEOUT
который по умолчанию составляет 10 секунд. Это особенно удобно, когда нужно проверить не несколько страниц, а большой список доменов или URL.
Что именно проверяет инструмент
Здесь важно понимать ограничение проверки.
Значение:
hsts = yes
означает, что в полученном ответе присутствует заголовок:
Strict-Transport-Security
Это еще не означает автоматически, что вся HSTS-конфигурация сайта идеальна.
Например, отдельно могут потребовать проверки:
- значение
max-age; - наличие
includeSubDomains; - наличие
preload; - HTTPS на всех поддоменах;
- корректность TLS-сертификатов;
- HTTP - HTTPS редиректы;
- попадание домена в реальный HSTS preload list.
Поэтому скрипт правильнее рассматривать как инструмент первичной массовой диагностики. Он быстро отвечает на вопрос: «На каких URL присутствует HSTS, а на каких его нет?»
После этого проблемные или интересующие домены можно анализировать подробнее.
Где такая проверка может пригодиться
На практике массовая проверка HSTS удобна при техническом аудите большого количества сайтов или доменов. Например, если есть список из нескольких сотен сайтов, вручную открывать каждый домен и искать нужный заголовок бессмысленно. Гораздо проще сформировать:
urls.txt
запустить проверку и отфильтровать в CSV строки:
hsts = no
Таким образом можно быстро выделить сайты, требующие дополнительного анализа HTTPS-конфигурации. А поскольку одновременно собирается информация об ETag, тот же проход дает дополнительные данные о настройках HTTP-ответов.
Итог
HSTS — достаточно простой по форме, но важный по смыслу механизм.
Обычный HTTPS и HTTP - HTTPS редирект защищают соединение после перехода на защищенный протокол. HSTS идет дальше и позволяет браузеру запомнить, что обращаться к определенному домену через HTTP вообще не следует.
Базовая политика задается одним заголовком:
Strict-Transport-Security: max-age=31536000
а дополнительные директивы позволяют распространить ее на поддомены и подготовить домен к HSTS Preload.
При этом чем жестче политика, тем внимательнее необходимо проверять инфраструктуру перед ее включением. Для единичного сайта наличие HSTS легко проверить вручную. Если же нужно пройти десятки, сотни или тысячи URL, удобнее автоматизировать процесс. Для такой задачи можно использовать мой hsts-etag-checker — небольшой Python-скрипт, который принимает список URL и формирует CSV с HTTP-статусами и информацией о наличии HSTS и ETag.
Это не полноценный аудит безопасности и не валидатор всей HSTS-конфигурации, а простой инструмент первичной массовой проверки HTTP-заголовков — именно в этом сценарии он и наиболее полезен.
