Перейти к содержимому
🚀 Уже доступно 10 инструментов, бесплатно навсегда — и список растёт
Главная›Блог›Заголовки безопасности HTTP: полное руководство по CSP, HSTS и остальным
Руководства

Заголовки безопасности HTTP: полное руководство по CSP, HSTS и остальным

Горстка заголовков ответа решает, запустит ли браузер внедрённый скрипт, поместит ли ваши страницы в рамку и откатится ли на незашифрованный HTTP. В руководстве — что делает каждый, какие стоят усилий и как внедрить строгую CSP, ничего не сломав.

✍ Автор — основатель и CEO, команда BuildToolForge🗓 2026-10-12⏱ 12 мин
securitycsphstsheadershttp
Руководство по веб-безопасности2026

Заголовки
На практике

CSP, HSTS и четыре небольших заголовка — построчно

Готовые политики · План внедрения · Без регистрации

curl -I · example.com
$ curl -I https://example.com
CSPdefault-src 'self'nonce
HSTSmax-age=31536000
XCTOnosniff
Refstrict-origin-when-cross
✓ 6 из 6 заголовков · без unsafe-inline
Заголовки
CSP
Что может загрузиться
HSTS
Только HTTPS
XCTO
Без угадывания MIME
Referrer
Что утекает
Permissions
Доступ к устройствам
COOP
Изоляция окон
Блокирует внедрённые скриптыНе даёт откатиться на HTTPПредотвращает кликджекингОграничивает утечкиПроверка бесплатна

Большая часть безопасности сайта живёт в его коде, но небольшой набор заголовков ответа HTTP решает, что браузер согласится делать с этим кодом, когда тот до него доберётся. Это разница между внедрённым <script>, который исполняется, и тем, который браузер отказывается запускать; между первым визитом по незашифрованному HTTP и визитом, который поднимается до HTTPS ещё до того, как покинет адресную строку.

К тому же их необычно дешево внедрять. Заголовок — это конфигурация, а не код: большинство из них укладывается в одну строку на вашем веб-сервере, в CDN или фреймворке и действует сразу на все ответы. В руководстве разобрано, что делает каждый заголовок, какие из них себя оправдывают, как внедрить Content-Security-Policy, не сломав собственный сайт, и как проверить, что вы отправляете сегодня.

Почему заголовки безопасности важны

Заголовок — это инструкция браузеру, а браузер — единственная сторона, способная выполнить её на машине пользователя. Это делает заголовки второй линией обороны, которая держится, даже когда выше по течению уже что-то пошло не так:

  • Они сдерживают уже допущенные ошибки. Content-Security-Policy не закрывает дыру XSS, но может не дать внедрённому скрипту запуститься или что-либо отправить обратно.
  • Они закрывают целые классы атак. Кликджекинг, путаница MIME-типов и откат на HTTP — не ошибки в вашем коде, а поведение браузера, от которого нужно явно отказаться.
  • Они останавливают тихие утечки данных. Без политики реферера полный URL приватной страницы уезжает к каждой третьей стороне, с которой вы подгружаете картинку.
  • Это первое, на что смотрит аудитор. Отсутствующие заголовки всплывают в каждом автоматическом сканировании, опроснике по безопасности и проверке поставщика, потому что это самая дешёвая из возможных находок.

Загвоздка в том, что их легко сделать почти правильно. CSP с unsafe-inline блокирует очень мало; заголовок HSTS со сроком в один день почти никого не защищает. Вся ценность — в деталях.

Заголовки, которые важнее всего

Шесть заголовков делают почти всю полезную работу. Остальные либо унаследованы, либо крайне узки, либо вытеснены.

ЗаголовокЧто предотвращаетТрудозатраты
Content-Security-PolicyXSS, выгрузку данных, неожиданный сторонний кодВысокие
Strict-Transport-SecurityОткат на HTTP, кражу cookie при первом запросеНизкие
X-Content-Type-OptionsИсполнение загруженного файла как скриптаМинимальные
Referrer-PolicyУтечку полных URL третьим сторонамМинимальные
Permissions-PolicyДоступ к камере, микрофону и геолокацииНизкие
Cross-Origin-Opener-PolicyАтаки через окна со страниц, которые вы открываетеНизкие

Начните снизу. Четыре дешёвых заголовка — по одной строке каждый, и они почти никогда ничего не ломают, так что их стоит отправить уже сегодня; плана требует именно CSP.

Content-Security-Policy

CSP — это список разрешённого, сообщающий браузеру, откуда может приходить каждый вид ресурсов. Достаточно строгая политика выглядит так:

default-src 'self'; script-src 'self' 'nonce-r4nd0m'; style-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; object-src 'none'

Читайте директиву за директивой. default-src 'self' — запасной вариант: всё, что не названо явно, может загружаться только с вашего собственного источника. script-src важнее всего, потому что именно скрипты злоумышленник хочет запустить. frame-ancestors 'none' запрещает любому другому сайту помещать вашу страницу в iframe и является современной заменой X-Frame-Options. object-src 'none' и base-uri 'self' закрывают два старых обходных пути, перекрыть которые ничего не стоит.

Два значения решают, настоящая ли ваша политика. 'unsafe-inline' в script-src разрешает любой встроенный <script>, включая внедрённый злоумышленником, — то есть ровно то, ради предотвращения чего CSP и существует. 'unsafe-eval' разрешает eval() и его родственников. Политика с любым из них всё ещё полезна для нескриптовых директив, но от XSS она вас не защищает.

Выход — nonce или хеш. Nonce — случайное значение, генерируемое на каждый ответ и прикрепляемое и к заголовку, и к каждому легитимному <script nonce="...">; браузер запускает только скрипты с этим значением, а внедрённый скрипт его не угадает. Хеши работают так же для скриптов, которые никогда не меняются. Если ваш фреймворк отдаёт встроенные скрипты, почти наверняка поддержка nonce в нём уже есть — обычно её достаточно включить в настройках.

Strict-Transport-Security

HSTS предписывает браузеру отказывать в незашифрованном HTTP для вашего домена на заданный срок, и это закрывает щель, которую один редирект оставляет открытой: самый первый запрос, до того как редирект доедет, идёт в открытом виде и может быть перехвачен.

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

max-age задаётся в секундах; обычная цель — год, а меньше нескольких месяцев даёт мало. includeSubDomains распространяет правило на все поддомены — именно это делает его действенным и именно это стоит проверить первым: любой поддомен, который всё ещё отдаётся по HTTP, перестанет работать. preload запрашивает включение в список, который браузеры поставляют с собой, так что защищён даже первый визит.

Считайте HSTS трудно обратимым. Браузер, увидевший годовую политику, будет применять её год, что бы вы ни отправили потом. Внедряйте с коротким max-age, убедитесь, что ничего не сломалось, и только затем увеличивайте. И поскольку HSTS имеет смысл лишь при действительном сертификате, проверьте сертификат и его срок с помощью проверки SSL-сертификата, прежде чем брать на себя долгую политику.

Небольшие заголовки

Эти четыре — по одной строке каждый и редко вызывают споры:

  • X-Content-Type-Options: nosniff — не даёт браузеру угадывать тип ответа по его содержимому. Без него файл, загруженный как .txt, может быть исполнен как скрипт, если браузер решит, что он на скрипт похож.
  • Referrer-Policy: strict-origin-when-cross-origin — отправляет полный URL на ваш собственный источник, только источник — на другие HTTPS-сайты и ничего — при переходе на HTTP. Это современное значение по умолчанию, и оно не даёт приватным путям и параметрам утекать третьим сторонам.
  • Permissions-Policy: camera=(), microphone=(), geolocation=() — отключает возможности устройства, которыми ваш сайт не пользуется, и для вашей страницы, и для всего, что вы встраиваете.
  • Cross-Origin-Opener-Policy: same-origin — разрывает оконную связь со страницами, которые вы открываете или которые открывают вас, что блокирует целое семейство атак через окна и является предварительным условием для некоторых механизмов изоляции в браузере.

X-Frame-Options: DENY всё ещё уместен для старых браузеров, но frame-ancestors в вашей CSP заменяет его и выразительнее. Отправляйте оба: они не конфликтуют.

Как безопасно внедрить CSP

CSP, написанная наугад, заблокирует что-то нужное вашему же сайту. Путь «сначала отчёты» избавляет от этого полностью:

  1. Отправьте четыре дешёвых заголовка сегодня. nosniff, политику реферера, политику разрешений и HSTS с коротким max-age. Ни один из них обычно не ломает работающий сайт.
  2. Добавьте Content-Security-Policy-Report-Only. Синтаксис тот же, но браузер только сообщает о нарушениях, а не блокирует их. Сайт ведёт себя точно как прежде.
  3. Собирайте отчёты одну-две недели. Они назовут каждый сторонний скрипт, шрифт, конечную точку аналитики и встроенный обработчик, о которых вы забыли. Этот шаг чаще всего пропускают, и именно он делает всё остальное безболезненным.
  4. Затягивайте, пока отчёты не стихнут. Добавьте источники, которые вам действительно нужны, и уберите те, в которых, как выяснилось, нужды нет. Не расширяйте директиву до *, чтобы заглушить один отчёт.
  5. Переключитесь на применение. Переименуйте заголовок в Content-Security-Policy. Оставьте рядом вариант report-only для будущей проверки более строгой политики.
  6. Уберите unsafe-inline последним. Это и есть настоящая работа: перенести встроенные скрипты в файлы или выдать им nonce. Всё предыдущее — подготовка; именно этот шаг останавливает XSS.

Практическое замечание: заголовки действуют на каждый ответ, поэтому задавайте их на границе — в CDN, обратном прокси или промежуточном слое фреймворка, — а не страница за страницей. Задать их в одном месте — ещё и единственный способ убедиться, что их несут и страницы ошибок, и редиректы, а именно там их обычно и не хватает.

Заголовки, которые можно больше не отправлять

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

  • X-XSS-Protection — фильтров браузера, которыми он управлял, больше нет. Ни в одном современном браузере он ничего не делает, а старое значение mode=block когда-то создавало собственные проблемы. Уберите его и опирайтесь на CSP.
  • Public-Key-Pins — HPKP удалён из браузеров. Было слишком легко закрыть себе доступ к собственному домену, поэтому от него отказались.
  • Expect-CT — прозрачность сертификатов теперь обеспечивается по умолчанию, так что заголовок избыточен.
  • Feature-Policy — переименован в Permissions-Policy с другим синтаксисом. Отправляйте новый; старый оставляйте только если нужно поддерживать что-то очень древнее.

Напротив, кое-что стоит убрать — сведения, которые вы выдаёте сами: заголовок Server или X-Powered-By с точной версией вашего фреймворка подсказывает злоумышленнику, какие эксплойты пробовать первыми. Это не уязвимость, но и публиковать это незачем.

Как проверить свои заголовки

Заголовки публичны, так что проверить настройку любого сайта можно за секунды:

  1. curl -I https://example.com. Запрос HEAD печатает все заголовки ответа, не загружая страницу. Добавьте -L, чтобы смотреть конечный URL, а не редирект.
  2. Панель «Сеть» в браузере. Откройте инструменты разработчика, перезагрузите страницу, выберите основной документ и прочитайте раздел заголовков ответа. Консоль к тому же записывает каждое нарушение CSP вместе с заблокировавшей директивой — это самый быстрый способ отладить политику.
  3. Проверка с оценкой результата. Наш инструмент проверки заголовков безопасности запрашивает URL и показывает, какие заголовки есть, каких не хватает и где имеющийся заголовок слабее, чем кажется.

Проверяйте не только главную. Заголовки часто выставлены на основном приложении, но не на хостах статики, страницах ошибок, поддоменах API или на редиректе с www на основной домен. Заодно убедитесь, что и сама цепочка редиректов верна; справочник кодов состояния HTTP объясняет, какой код подходит для постоянного переезда.

Чтобы составить политику, не заучивая синтаксис, начните с нашего генератора CSP — он также отмечает настройки, которые её ослабляют.

Типичные ошибки

  • CSP с unsafe-inline в script-src. Она проходит большинство автоматических проверок и почти не останавливает XSS. Используйте nonce или хеши.
  • Расширение директивы до * ради одного отчёта. Добавьте конкретный источник; * отказывается от директивы целиком.
  • HSTS с долгим max-age в первый же день. На опубликованный срок это практически необратимо. Начните с короткого.
  • includeSubDomains до проверки поддоменов. Всё, что осталось на HTTP, включая внутренние инструменты, перестаёт загружаться.
  • Заголовки в приложении, но не на границе. Страницы ошибок, редиректы и хосты статики остаются без защиты, а именно к этим ответам и тянутся злоумышленники.
  • Один и тот же заголовок дважды. Два заголовка CSP пересекаются, а не объединяются, поэтому результат строже каждого из них и обычно что-то ломает; два противоречащих значения X-Frame-Options могут быть проигнорированы целиком.
  • Всё ещё отправлять X-XSS-Protection и считать дело сделанным. Мёртвый заголовок даёт ложное спокойствие в отчёте.
  • Никогда не выходить из режима report-only. Отчёты, по которым вы не действуете, никого не защищают.

Проверьте свои заголовки

Заголовки безопасности дают лучшее соотношение защиты к усилиям, какое есть в интернете: четыре из них — по одной строке, а пятый, CSP, сводится в основном к тому, чтобы выслушать собственные отчёты о нарушениях прежде, чем что-либо применять. Начните с того, что ваш сайт отправляет сегодня, добавьте дешёвые заголовки сразу, а затем включите CSP в режиме report-only и дайте ей рассказать, что должна содержать ваша политика.

Связанные инструменты и руководства:

Частые вопросы

Какие заголовки безопасности добавить первыми?⌄

Начните с четырёх, которые почти никогда ничего не ломают: X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy, отключающая неиспользуемые возможности устройства, и Strict-Transport-Security с коротким max-age, который вы потом увеличите. Затем добавьте Content-Security-Policy в режиме report-only, потому что именно она требует наблюдения до применения.

Помогает ли CSP с unsafe-inline?⌄

Помогает во всём, кроме той атаки, которую CSP останавливает лучше всего. Директивы img-src, connect-src, frame-ancestors и object-src по-прежнему ограничивают, куда могут уйти данные и кто может поместить вас в рамку. Но 'unsafe-inline' в script-src разрешает запуск любого внедрённого встроенного скрипта, так что от XSS политика не защищает. Замените его на nonce для каждого ответа или на хеши скриптов.

Опасен ли Strict-Transport-Security?⌄

Опасен прежде всего тем, что его трудно отменить: браузер, увидевший max-age=31536000, будет отказывать в незашифрованном HTTP для вашего домена год, что бы вы ни отправили дальше. Внедрите сначала с коротким max-age, убедитесь, что каждый поддомен доступен по HTTPS, прежде чем добавлять includeSubDomains, и только потом увеличивайте срок и думайте о preload.

Что заменило X-Frame-Options и X-XSS-Protection?⌄

Директива frame-ancestors в Content-Security-Policy заменяет X-Frame-Options и выразительнее, хотя отправлять оба безвредно и до сих пор помогает старым браузерам. У X-XSS-Protection замены нет, потому что фильтры браузера, которыми он управлял, были удалены; XSS теперь останавливает CSP, а старый заголовок можно просто убрать.

Где следует задавать заголовки безопасности?⌄

На границе, в одном месте: в CDN, обратном прокси или промежуточном слое фреймворка. Если задавать их постранично, без прикрытия останутся страницы ошибок, редиректы, хосты статики и ответы API — именно те ответы, что упускают при аудите и выбирают при атаке.

Как узнать, какие заголовки отправляет мой сайт?⌄

Запустите curl -I https://ваш-домен.ru, добавив -L, чтобы увидеть конечный адрес, а не редирект, либо откройте панель «Сеть» в браузере и прочитайте заголовки ответа для основного документа. Инструмент проверки заголовков безопасности делает это из браузера и отмечает как отсутствующие заголовки, так и присутствующие, которые слабее, чем выглядят.

Об авторе
Основатель и CEO, BuildToolForge
Мы в X: @Buildtoolforge

Более 15 лет практического опыта в веб-разработке и безопасности. Специализация — практическая веб-безопасность: чтобы сайты были защищёнными, надёжными и легко диагностировались. BuildToolForge создан, чтобы такие проверки были бесплатными, приватными и понятными. Инструменты по возможности работают прямо в браузере, а всё, что вы вводите в инструмент, не сохраняется.

Как мы пишем руководства: Каждое руководство основано на практическом опыте, сверено с официальными стандартами и проверено нашими инструментами на реальных доменах. Мы обновляем руководства, когда меняются стандарты или инструменты. Нашли ошибку? Напишите нам: contact@buildtoolforge.com.

Последнее обновление: 2 ноября 2026 г.