Короткий ответ: чтобы подтвердить текущую серверную настройку HSTS, проверьте HTTPS-ответы каждого hostname в цепочке и найдите Strict-Transport-Security с корректным max-age. Браузер принимает валидный HSTS и из промежуточного HTTPS-редиректа; финальный ответ проверяют отдельно как репрезентативный пользовательский ответ и для контроля единообразия конфигурации. Проверка http://, автоматический переход браузера на HTTPS и старое состояние браузера сами по себе ничего из этого не доказывают.
Если сканер пишет «не зафиксирован HSTS», сначала выясните, какой URL и hostname он запросил и какие HTTPS-ответы цепочки анализировал. Такая формулировка может означать реальное отсутствие заголовка, проверку другого host или только HTTP-ответа, а также то, что инструмент проигнорировал HSTS на промежуточном HTTPS-редиректе.
Надёжная проверка отвечает сразу на три вопроса:
- Какие URL и hostname встретились до и после редиректов?
- В каких именно HTTPS-ответах пришёл
Strict-Transport-Security? - Не объясняется ли поведение браузера ранее сохранённой политикой или preload-списком?
Что значит «HSTS включён»
HSTS (HTTP Strict Transport Security) — политика браузера: после получения заголовка по защищённому соединению браузер запоминает, что этот host нужно открывать только по HTTPS. В дальнейшем он может заменить http:// на https:// ещё до отправки небезопасного HTTP-запроса.
У фразы «HSTS включён» есть два разных смысла:
- серверная конфигурация действует сейчас: внешний HTTPS-ответ содержит заголовок;
- конкретный браузер уже знает политику: он получил её раньше, унаследовал через
includeSubDomainsили имеет домен в preload-списке.
Эти состояния не всегда совпадают. Сервер мог перестать отдавать заголовок, но ранее получивший его браузер продолжит применять политику до окончания max-age. И наоборот: сервер уже отдаёт HSTS, но новый клиент ещё не посетил HTTPS-версию и не знает о политике, если домен не предзагружен.
Быстрая проверка через curl
Для URL без редиректов достаточно запросить заголовки по HTTPS:
curl -sS -D - -o /dev/null https://example.ru/
В ответе ищите строку вида:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Ключевой признак — не конкретное большое число, а наличие корректной директивы max-age в HTTPS-ответе. Значение задаёт срок хранения политики в секундах. max-age=0 означает команду удалить сохранённую политику после получения такого ответа по HTTPS, поэтому считать её включённой нельзя.
Как не потерять финальный ответ за редиректами
Обычная проверка первого URL может показать только 301 или 302. Сначала зафиксируйте, куда реально пришёл запрос:
curl -sS -L -o /dev/null \
-w 'final_url=%{url_effective}\nstatus=%{http_code}\n' \
https://example.ru/
Затем запросите напечатанный final_url отдельно командой с -D -. Так вы увидите заголовки именно финального ответа, а не смешанный список всех ответов цепочки.
Проверьте, что финальный адрес всё ещё относится к тому host, политику которого вы исследуете. Например, запрос к https://example.ru/ может завершиться на https://www.example.ru/. Заголовок от www.example.ru подтверждает конфигурацию www, но не доказывает, что тот же заголовок отдаёт example.ru.
Если установлен современный curl с поддержкой вывода заголовка через write-out, итог можно получить одной диагностической командой:
curl -sS -L -o /dev/null \
-w 'final_url=%{url_effective}\nstatus=%{http_code}\nhsts=%header{strict-transport-security}\n' \
https://example.ru/
Пустое hsts= означает только, что поле не найдено в финальном ответе. Проверьте каждый предшествующий HTTPS-ответ отдельно: валидный HSTS на таком редиректе уже может обновить политику этого hostname. Отсутствие поля на финальном ответе всё равно полезно зафиксировать как непоследовательность конфигурации.
Почему проверка по HTTP даёт ложный вывод
Такой запрос проверяет редирект, но не установку HSTS:
curl -sS -D - -o /dev/null http://example.ru/
Даже если незащищённый ответ содержит Strict-Transport-Security, браузер должен его игнорировать. Политика принимается только по HTTPS. Правильная последовательность для клиента без сохранённого HSTS обычно выглядит так:
http://example.ru/
→ HTTP-редирект на https://example.ru/
→ HTTPS-ответ или HTTPS-редирект с Strict-Transport-Security
Редирект и HSTS решают связанные, но разные задачи. Редирект отвечает клиенту, который уже отправил HTTP-запрос. Сохранённая HSTS-политика позволяет браузеру перейти на HTTPS до такого запроса. Поэтому наличие 301 Location: https://... не равно наличию HSTS.
Проверка в DevTools
Откройте страницу по явному адресу https://..., затем инструменты разработчика и вкладку Network. Перезагрузите страницу и выберите основной запрос документа. В деталях запроса проверьте:
- Request URL — точный URL и hostname каждого шага;
- Status Code — код каждого ответа, включая HTTPS-редиректы;
- Response Headers — наличие и значение
strict-transport-securityв каждом HTTPS-ответе; - цепочку перенаправлений, если браузер показывает предыдущие запросы отдельно;
- hostname каждого шага: apex-домен,
wwwи другие поддомены нельзя смешивать.
Не ищите заголовок только в HTML-коде страницы. HSTS — поле HTTP-ответа; запись в <meta http-equiv> не устанавливает эту политику.
Опция Disable cache полезна, чтобы уменьшить влияние обычного HTTP-кэша при перезагрузке, но она не превращает браузер в чистый HSTS-клиент. Сохранённая HSTS-политика живёт отдельно от кэша ресурсов. Автоматическое открытие HTTPS может быть вызвано прежним посещением, политикой родительского домена с includeSubDomains или preload.
Как отличить отсутствие заголовка от ошибки проверки
Проверен не тот hostname
HSTS привязан к доменному имени, а не к сертификату или IP-адресу. Ответ www.example.ru не является прямым доказательством для example.ru, а запрос к IP не проверяет HSTS-политику домена.
Составьте явный список имён и проверяйте каждое отдельно:
example.ru
www.example.ru
api.example.ru
Заголовок был только на промежуточном ответе
CDN, балансировщик и приложение могут добавлять заголовки на разных шагах. Валидный HSTS на промежуточном HTTPS-ответе уже обрабатывается браузером для hostname этого ответа. Если поле есть на раннем HTTPS-301, но отсутствует на финальном 200, это не отменяет принятую политику, однако показывает непоследовательность конфигурации; мониторинг должен сообщать о ней отдельно.
Проверен HTTP-ответ
Заголовок на http:// не устанавливает HSTS. Перейдите по Location и исследуйте HTTPS-ответ отдельно.
Ответ пришёл из другого маршрута
Разные пути, CDN-узлы, IPv4/IPv6, virtual host или резервный балансировщик могут выдавать разные заголовки. Зафиксируйте финальный URL, DNS-имя, время и точку проверки. Если расхождение повторяется, сравните внешние ответы с разных разрешённых сетей и конфигурацию точки завершения TLS.
Браузер помнит старую политику
Если адрес мгновенно переписывается на HTTPS, это не доказывает наличие заголовка сегодня. Сначала проверьте текущий HTTPS-ответ через curl или Network. Затем учитывайте профиль браузера и preload. Простая очистка файлов и изображений из кэша может не удалить HSTS-состояние.
Заголовка нет только на части ответов
Проверьте не только главную страницу, но и типовые ответы того же hostname: канонический редирект, обычную страницу и контролируемый 404. Один успешный ответ способен обновить политику браузера, однако пропуски на отдельных ветках часто указывают, что заголовок добавляется приложением, а не единым внешним HTTPS-слоем.
Как читать директивы
max-age
Strict-Transport-Security: max-age=31536000
Число задаёт, сколько секунд браузер хранит политику после получения заголовка. При последующих HTTPS-ответах срок обновляется. Если в одном текущем ответе заголовок исчез, уже сохранённая политика не прекращается немедленно: она действует до своего срока.
includeSubDomains
Strict-Transport-Security: max-age=31536000; includeSubDomains
Директива распространяет политику вниз по доменному дереву. Политика от example.ru может охватить www.example.ru, но политика от www.example.ru не поднимается на example.ru и не распространяется на соседний api.example.ru.
При проверке поддомена учитывайте два возможных источника: его собственный заголовок и унаследованную политику родительского имени. Наличие наследования не отменяет проверку текущего HTTPS-ответа самого сервиса.
preload
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
preload — не часть базового механизма RFC 6797 и не команда браузеру немедленно добавить домен в список. Предзагрузка требует отдельной подачи домена и выполнения актуальных требований сервиса preload. Браузер с таким списком может применять HTTPS ещё до первого сетевого получения HSTS-заголовка.
Поэтому проверяйте preload отдельно от заголовка:
- есть ли нужные директивы в текущем HTTPS-ответе;
- подан ли домен в preload-сервис и каков его статус;
- содержит ли используемая версия браузера соответствующую запись.
Одна лишь директива preload в ответе не доказывает второй и третий пункты.
Безопасный сценарий приёмки
- Запишите точный исходный URL и ожидаемый hostname.
- Через curl зафиксируйте каждый URL, hostname и код в цепочке редиректов.
- Сохраните заголовки каждого HTTPS-ответа, включая промежуточные редиректы и финальный ответ.
- Для каждого hostname отметьте, где присутствует
Strict-Transport-Securityи содержит ли он ожидаемыйmax-age. - Отдельно отметьте
includeSubDomainsиpreload; не считайте их обязательными для любой HSTS-политики. - Повторите проверку в DevTools для основного документа, сверив Request URL и Response Headers.
- Сравните поведение обычного профиля с результатом сетевой проверки, не используя автоматический переход как единственное доказательство.
- Проверьте сертификат и HTTPS отдельно: HSTS не исправляет срок, имя или цепочку сертификата.
Если заголовок отсутствует, сначала сохраните факты: URL, время, код, цепочку редиректов и ответные заголовки. Не очищайте HSTS-состояние рабочего браузера и не меняйте серверную политику только ради эксперимента, особенно если действует большой max-age.
Что включить в мониторинг
Разовая проверка подтверждает состояние только в конкретный момент и на конкретном маршруте. Для контроля HSTS мониторинг должен:
- обращаться к каноническому публичному URL по HTTPS;
- следовать только ожидаемому числу редиректов и сохранять всю цепочку URL;
- проверять точный hostname каждого HTTPS-ответа, а не только доступность IP;
- фиксировать корректный
Strict-Transport-Securityна каждом шаге и отдельно контролировать его наличие на финальном ответе как правило единообразной эксплуатации; - разбирать
max-ageкак число и сверять его с принятой политикой; - отдельно фиксировать наличие
includeSubDomainsиpreload, если они действительно предусмотрены; - сигнализировать о неожиданной смене host, пропаже заголовка и
max-age=0; - параллельно контролировать срок, имя и цепочку TLS-сертификата.
Не сводите проверку к поиску строки в объединённом наборе заголовков: так теряется связь политики с конкретным HTTPS-ответом и hostname. Валидный HSTS на промежуточном HTTPS-редиректе действует, а отсутствие поля на финальном ответе следует показывать как отдельную эксплуатационную непоследовательность. Успешный HTTPS-код сам по себе HSTS не подтверждает.
Если curl и DevTools показывают разные hostname, редиректы или заголовки, запустите SSL-проверку Web‑Puls и приложите к обращению финальный URL, время и сохранённые заголовки без cookie. Такая диагностика помогает проверить внешний HTTPS-маршрут и сертификат; состояние локального HSTS-хранилища браузера всё равно нужно оценивать на самом клиенте.