Security headers: какие HTTP-заголовки проверять на сайте
HTTP-заголовки безопасности задают браузеру ограничения: откуда разрешено загружать скрипты, можно ли открыть страницу во фрейме, сколько информации передавать при переходе и допустим ли доступ к отдельным API устройства. Проверка security headers нужна не ради максимального числа директив, а ради понятной и воспроизводимой политики защиты, которая соответствует устройству сайта.
Какую проблему решают защитные заголовки
Сервер возвращает заголовки вместе с HTML, изображениями и другими ресурсами. Браузер читает их до выполнения клиентского кода и применяет заданные ограничения. Это позволяет уменьшить последствия внедрения постороннего скрипта, запретить встраивание страницы на чужом домене, отключить определение MIME-типа по содержимому и ограничить передачу адреса исходной страницы.
Заголовки не исправляют уязвимый код и не заменяют проверку прав доступа, валидацию входных данных или безопасную работу с сессиями. Они образуют дополнительный уровень защиты. Поэтому результат проверки следует формулировать точно: заголовок присутствует, его синтаксис корректен, политика соответствует выбранной модели и не нарушает работу интерфейса.
Какие security headers проверять
| Заголовок | Что контролирует | Практический критерий |
|---|---|---|
Content-Security-Policy |
Источники скриптов, стилей, изображений, фреймов и подключений | Есть ограничивающие директивы; отсутствуют ненужные широкие разрешения; все функции сайта проверены |
Strict-Transport-Security |
Принудительное обращение браузера к сайту по HTTPS | Отправляется только по HTTPS; max-age выбран осознанно; поддомены готовы до добавления includeSubDomains |
X-Content-Type-Options |
Запрет MIME-sniffing | Значение равно nosniff, а сервер отдает корректные Content-Type |
Referrer-Policy |
Объем данных в заголовке Referer |
Выбрана явная политика, например strict-origin-when-cross-origin |
Permissions-Policy |
Доступ страницы и фреймов к камере, микрофону, геолокации и другим функциям | Неиспользуемые возможности отключены, нужные интеграции не заблокированы |
frame-ancestors в CSP |
Домены, которым разрешено встраивать страницу | Указано 'none', 'self' или ограниченный список доверенных источников |
X-Frame-Options |
Устаревшая защита от нежелательного встраивания | DENY или SAMEORIGIN для совместимости; основное правило задано через CSP |
Content-Security-Policy: самый чувствительный заголовок
CSP способен заметно снизить риск выполнения постороннего кода, но именно он чаще всего ломает интерфейс при поспешном включении. Базовая политика может содержать default-src 'self', отдельные правила script-src, style-src, img-src, connect-src, а также object-src 'none' и base-uri 'self'. Универсального готового значения нет: допустимые источники зависят от аналитики, карт, платежных форм, CDN и других интеграций.
Разрешения *, 'unsafe-inline' и 'unsafe-eval' ослабляют политику. Иногда они временно необходимы старому приложению, но их наличие следует зафиксировать как технический долг. Для встроенных скриптов предпочтительны nonce или хеши. Начинать безопаснее с Content-Security-Policy-Report-Only: браузер сообщает о нарушениях, но не блокирует ресурсы. После анализа отчетов и консоли политика переводится в режим блокировки.
Дополнительная изоляция
Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy и Cross-Origin-Embedder-Policy усиливают межсайтовую изоляцию. Их нельзя добавлять механически: они способны повлиять на всплывающие окна, авторизацию через внешнего провайдера, виджеты и загрузку ресурсов с CDN. Такие заголовки проверяют после основных политик и только вместе с функциональными тестами.
Диагностический алгоритм
- Зафиксируйте точки проверки. Возьмите главную страницу, типовую внутреннюю страницу, форму входа или заказа, страницу ошибки и URL после редиректа. Заголовки могут различаться между приложением, CDN и обработчиком ошибок.
-
Получите фактический ответ сервера.
Для проверки GET-запросом используйте:
Для цепочки перенаправлений добавьтеcurl -sS -D - -o /dev/null https://example.ru/page-L. Проверяйте каждый ответ в цепочке отдельно: промежуточный редирект и конечная HTML-страница могут формироваться разными системами. - Сверьте ответ в браузере. В DevTools откройте вкладку Network, перезагрузите страницу и изучите Response Headers у основного документа. Консоль покажет ресурсы, заблокированные CSP, и часть конфликтов политик.
-
Оцените не только наличие, но и значение.
Пустой CSP, чрезмерно широкие источники или HSTS с символическим
max-ageне дают ожидаемой защиты. Одновременно слишком жесткая политика может заблокировать форму, шрифт или запрос к API. - Вносите изменения по одному уровню. Сначала настройте заголовок на тестовом окружении, затем проверьте ключевые сценарии, разверните изменение и повторно снимите ответы с публичных URL.
Чек-лист безопасного внедрения
- CSP соответствует реальным источникам ресурсов и сначала проверена в режиме Report-Only.
- В
script-srcнет необоснованных*,'unsafe-inline'и'unsafe-eval'. - Встраивание ограничено директивой
frame-ancestors; совместимость сX-Frame-Optionsучтена. X-Content-Type-Options: nosniffсопровождается корректными MIME-типами CSS, JavaScript и файлов.- Политика
Referrer-Policyявно задана и не раскрывает лишние части URL внешним сайтам. Permissions-Policyзапрещает неиспользуемые функции, но сохраняет работу необходимых виджетов.- Заголовки присутствуют на успешных ответах, редиректах и страницах ошибок там, где это применимо.
- После изменения проверены меню, формы, авторизация, поиск, аналитика, внешние виджеты и запросы API.
Типовые ошибки конфигурации
Копирование чужого набора. Политика другого проекта отражает его домены и интеграции. На новом сайте она либо ничего не ограничит, либо заблокирует необходимые ресурсы.
Дублирование на разных уровнях. Заголовок может добавляться приложением, веб-сервером и CDN одновременно. Для некоторых заголовков несколько значений меняют итоговую интерпретацию. Источник каждого значения нужно определить и оставить единую управляемую конфигурацию.
Проверка только главной. Административные маршруты, формы, страницы ошибок и ответы из кеша могут иметь другой набор заголовков. Репрезентативная выборка URL надежнее единичного теста.
Резкое включение строгой CSP. Ошибки часто проявляются не при загрузке страницы, а после открытия модального окна, отправки формы или входа через внешний сервис. Поэтому нужен список пользовательских сценариев, а не только визуальный осмотр первого экрана.
Ставка на устаревшие директивы. Например, X-XSS-Protection не следует считать современной заменой CSP. Устаревшие или неподдерживаемые механизмы не должны создавать ложное ощущение закрытого риска.
Границы метода
Анализ заголовков описывает только поведение браузера при обработке HTTP-ответа. Он не подтверждает отсутствие XSS, ошибок авторизации, утечки секретов, уязвимых зависимостей или небезопасной серверной логики. В этой статье также не рассматриваются настройка сертификатов, mixed content и общий аудит безопасности: это отдельные задачи с собственными критериями.
Публичная проверка видит то, что сервер отдает конкретному URL и клиенту. Ответ может зависеть от региона, авторизации, эксперимента, прокси или CDN. Для критичных маршрутов результаты стоит дополнять проверкой конфигурации на стороне инфраструктуры и тестами в разных состояниях пользователя.
Итог
Хорошая конфигурация security headers — это не самый длинный список заголовков, а минимальный набор осознанных ограничений. Начните с инвентаризации ответов, внедряйте CSP через Report-Only, проверяйте значения на нескольких маршрутах и подтверждайте работу ключевых функций после каждого изменения. Итоговую конфигурацию полезно хранить рядом с кодом или инфраструктурными настройками, чтобы изменения проходили ревью и повторную проверку.
SiteVisor анализирует публичный URL без доступа к CMS и помогает увидеть технические, SEO/GEO и конверсионные сигналы страницы. Чтобы получить исходную точку для дальнейшей ручной диагностики, запустите бесплатную проверку. Другие практические материалы собраны в блоге SiteVisor.