Заголовки безопасности — объяснение

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

Заголовки — это инструкции для браузера, а не броня сервера

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

Они также являются эшелонированной защитой, и читать их следует именно так. Канонические ссылки для этой области — документация MDN по HTTP, которая определяет синтаксис и семантику каждого заголовка, и проект OWASP Secure Headers Project, на рекомендуемые значения которого указывает руководство по тестированию в OWASP Web Security Testing Guide. Ни один из источников не обещает, что заголовки сделают сайт безопасным. Они обещают нечто более узкое и верное: с установленными заголовками целые классы атак, исполняемых браузером, перестают работать, даже когда баг приложения даёт атакующему точку опоры.

Что каждый заголовок на самом деле останавливает

Content-Security-Policy останавливает выполнение внедрённых скриптов. XSS и его родственники — сохранённый комментарий со скриптом, скимминговый скрипт, внедрённый через скомпрометированный сторонний тег, — все нуждаются в том, чтобы браузер выполнил код, которого сайт никогда не намеревался выполнять. CSP — это список разрешённого: script-src называет источники, откуда могут приходить скрипты, а всё остальное, включая встроенные скрипты и всё загруженное с сервера атакующего, отклоняется. Её слабые формы знамениты: политика, содержащая 'unsafe-inline', позволяет запускаться каждому встроенному скрипту, включая внедрённый, и поэтому проверяющий инструмент обращается с такой политикой как со слабой, а не хорошей. CSP — самый тяжёлый заголовок при развёртывании и тот, что останавливает больше всего.

Strict-Transport-Security останавливает понижение. В первый раз, когда посетитель вводит ваш домен без схемы или следует по старой ссылке http://, этот запрос пересекает сеть в открытом виде, где его можно ободрать, перенаправить или прочитать — включая cookie сессии. HSTS говорит браузеру: на следующие max-age секунд переписывай каждый URL http:// для этого хоста на https:// до того, как что-либо покинет машину, и отвергай проход сквозь ошибки сертификата. Одно честное ограничение: HSTS защищает только посетителей, чьи браузеры уже видели заголовок один раз (встроенные в браузеры списки предзагрузки существуют, чтобы закрыть ровно этот разрыв первого визита), и он соблюдается, только когда сам прибывает по HTTPS.

Защита от фреймов останавливает кликджекинг. Если ваши страницы можно встроить во фрейм, враждебный сайт может разложить ваш настоящий интерфейс под прозрачным слоем собственных кнопок и собирать клики — жертва видит безобидную на вид страницу и одобряет перевод. Директива CSP frame-ancestors (и её старшая сестра, X-Frame-Options: DENY или SAMEORIGIN) называет, кто может вас обрамлять; все остальные получают пустой фрейм. X-Content-Type-Options: nosniff останавливает более тихий трюк: браузеры исторически перегадывали объявленный Content-Type и исполняли файлы как скрипты или HTML, когда содержимое на то походило, превращая невинную загрузку в сохранённый XSS. nosniff заканчивает угадывание — объявленный тип и есть тип.

Referrer-Policy останавливает утечку URL. Когда посетитель кликает с вашей страницы на другой сайт, браузер исторически отправлял полный URL вашей страницы как Referer — включая любые сидящие в нём токены сброса пароля, поисковые запросы или идентификаторы записей. Политика strict-origin-when-cross-origin или строже отправляет между сайтами только источник и ничего — склонным к понижению целям http. Permissions-Policy останавливает злоупотребление функциями: она заявляет, какие мощные возможности браузера — камеру, микрофон, геолокацию, обработчики платежей — этот сайт вообще может использовать, чтобы внедрённый фрейм или скрипт не мог тихо запрашивать их от вашего имени. А бонусный заголовок, Cross-Origin-Opener-Policy, разрывает связь window.opener между вашей страницей и всплывающими окнами других источников, изолируя ваш контекст просмотра от страниц, которые могли бы его зондировать.

Почему так много сайтов получает F

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

Опубликованные цифры совпадают с этой историей. Опубликованная выборка одного сканера, сообщённая в еженедельном обзоре инструментов от 2026-11-04, обнаружила, что 65% просканированных сайтов получили F, а 51% не отправлял никакой Content-Security-Policy. Относитесь к ним как к тому, чем они являются, — выборке одного сканера, опубликованной третьей стороной, а не измерению всего веба и не нашим собственным данным, — но направление подтверждается опытом каждого оператора: заголовки — это та редкая мера безопасности, чьё отсутствие является статистической нормой. И это также хорошая новость, спрятанная в статистике: планка лежит на полу, а перешагнуть её — это конфигурация, а не инженерия.

Порядок исправлений — по влиянию на час

Работайте в том порядке, который делает очевидным проверка заголовков безопасности. Сначала однострочники: X-Content-Type-Options: nosniff, защита от фреймов и разумная Referrer-Policy — тридцать пять из ста баллов, несколько минут работы и практически нулевой риск поломки на обычном сайте. Вторым — HSTS, ещё двадцать баллов, но только после проверки того, что каждая страница, поддомен и унаследованное перенаправление действительно работают по HTTPS, потому что длинный max-age нельзя отправить обратно. Третьим — Permissions-Policy: перечислите функции, которые ваш сайт действительно использует, отключите остальные; десять баллов за одну тщательную строку.

Последней, и медленно, — CSP. Её 35 баллов — самый большой отдельный блок и единственное исправление, способное уложить ваш собственный сайт. Разверните её сначала как Content-Security-Policy-Report-Only с конечной точкой для отчётов, читайте неделю отчётов о нарушениях, переписывайте встроенные скрипты и обработчики событий, которые она помечает, — или примите nonce, как рекомендует руководство MDN, — и переходите к принудительному применению только тогда, когда отчёты затихнут. Добавляйте Cross-Origin-Opener-Policy: same-origin всякий раз, когда вы не зависите от межсайтовых сценариев всплывающих окон; в нашей таблице он не оценивается, но это дешёвая изоляция. Затем запустите проверку снова и подтвердите, что заголовки, добавленные на источнике, действительно пережили CDN и прокси перед ним.

Что заголовки не могут

Они не могут починить дыру, а только уменьшить то, что атакующий может сделать сквозь неё. CSP не чинит поле комментария, которое не экранировало свой ввод; она заставляет внедрённую полезную нагрузку отказаться запускаться. HSTS не чинит сломанную цепочку сертификатов — это территория оценщика SSL, — и никакой заголовок не заменяет установку исправлений, резервные копии или контроль доступа. Читайте идеальный класс заголовков как хорошо запертую дверь в здании, чьи остальные этажи по-прежнему нуждаются в собственных проверках, — для чего и существует проверка здоровья сайта.

Их также нельзя установить и забыть. CSP, написанная для прошлогоднего сайта, тихо блокирует платёжный виджет этого года — или, что хуже, в спешке ослабляется звёздочкой * и перестаёт что-либо значить. Обращайтесь с набором заголовков как с остальной вашей конфигурацией: под версионным контролем, пересматривайте при изменениях сайта и перепроверяйте после каждой смены платформы. Проверка занимает десять секунд; запускайте её всякий раз, когда меняется стек перед вашими страницами, и эпидемия F останется статистикой кого-то другого.

Источники и дополнительная литература

Часто задаваемые вопросы

Мой сайт получил F. С чего начать?

С однострочников: nosniff, защита от фреймов и Referrer-Policy возвращают 35 из 100 баллов за минуты и ничего не ломают. Затем HSTS, когда HTTPS проверен везде, затем Permissions-Policy, а CSP — последней, по пути Report-Only. Проверка заголовков безопасности даёт вам точную строку Nginx или Apache для каждого отсутствующего заголовка, чтобы вы могли пройти по собственной странице результатов по порядку.

Сломает ли Content-Security-Policy мой сайт?

Принудительно применяемая CSP может, если она запрещает встроенные скрипты или сторонние источники, которые вашим страницам действительно нужны, — это политика, выполняющая свою работу против кода, который никто не инвентаризировал. Безопасный путь — сначала Report-Only: браузер сообщает о нарушениях, ничего не блокируя, вы исправляете то, что отчёты выводят на поверхность, и принудительное применение вступает в силу только тогда, когда отчёты затихли. Никогда не заглушайте поломку добавлением 'unsafe-inline' или подстановочного символа; это сохраняет заголовок и теряет защиту.

Как часто следует перепроверять заголовки?

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