Практика
Заголовки безопасности: HTTPS, HSTS, CSP
Заголовки безопасности сайта за один день: HTTPS и HSTS, Content-Security-Policy, X-Content-Type-Options, Referrer-Policy, Permissions-Policy и значения.
Коротко. Заголовки безопасности сайта — это HTTP-заголовки, которые сервер отправляет вместе со страницей, чтобы браузер включил встроенную защиту: работал с сайтом только по HTTPS (Strict-Transport-Security), не выполнял посторонние скрипты (Content-Security-Policy), не угадывал тип файлов (X-Content-Type-Options), не передавал лишнее при переходах (Referrer-Policy), не давал странице доступ к камере и геолокации (Permissions-Policy) и не позволял встраивать сайт в чужие фреймы (директива frame-ancestors). За один рабочий день реально включить HTTPS с редиректом, HSTS с коротким сроком, простые заголовки и CSP в режиме отчётов. Блокирующую CSP включают через одну-две недели наблюдения. Заголовки не исправляют уязвимости в коде, но ограничивают последствия многих атак.
Статья для веб-разработчика, системного администратора или владельца сайта, которому нужно закрыть замечания сканера или пентестера по заголовкам и при этом не сломать сайт.
Что такое заголовки безопасности и от чего они защищают
Браузер умеет многое: запрещать загрузку скриптов с чужих доменов, отказываться от незашифрованного соединения, блокировать встраивание страницы во фрейм. Но большинство этих механизмов он включает только по указанию сайта — через заголовки ответа. Если их нет, браузер работает в режиме максимальной совместимости.
От чего защищают заголовки:
- перехват трафика при заходе по HTTP — HSTS;
- последствия XSS — внедрённый скрипт не загрузится с чужого домена и не отправит данные наружу — CSP;
- кликджекинг — страницу нельзя встроить в невидимый фрейм на чужом сайте — frame-ancestors;
- подмена типа файла — загруженный файл не будет выполнен как скрипт из-за «угадывания» типа — X-Content-Type-Options;
- утечка данных через Referer — параметры из адреса страницы не уйдут на сторонние сайты — Referrer-Policy;
- злоупотребление возможностями браузера — встроенный сторонний виджет не запросит камеру или микрофон — Permissions-Policy.
Отсутствие заголовков — одна из первых находок любого сканирования и частый пункт в отчётах о пентесте веб-приложения: в методике OWASP это раздел проверки конфигурации и развёртывания.
Заголовки безопасности сайта: что включить и какие значения взять
| Заголовок | Что делает | Стартовое значение | Чем опасна ошибка |
|---|---|---|---|
| Strict-Transport-Security | Браузер обращается к сайту только по HTTPS | max-age=86400, после проверки max-age=31536000 | Поддомены без HTTPS станут недоступны при includeSubDomains |
| Content-Security-Policy | Задаёт разрешённые источники скриптов, стилей, фреймов, отправки форм | Сначала в режиме Report-Only | Строгая политика сразу ломает аналитику, чаты, оплату |
| X-Content-Type-Options | Запрещает угадывать тип содержимого | nosniff | Файлы с неверным Content-Type перестанут загружаться |
| Referrer-Policy | Определяет, сколько адреса передаётся при переходе | strict-origin-when-cross-origin | Слишком строгое значение ломает часть партнёрской аналитики |
| Permissions-Policy | Определяет, какие возможности браузера доступны странице и фреймам | camera=(), microphone=(), geolocation=() | Отключённая нужная функция перестанет работать |
| CSP frame-ancestors | Определяет, кто может встраивать сайт во фрейм | frame-ancestors 'self' | Перестанут работать легитимные встраивания у партнёров |
| Атрибуты Set-Cookie | Защищают cookie сессии | Secure; HttpOnly; SameSite=Lax | Cookie без Secure и HttpOnly проще перехватить и украсть |
Про устаревшие заголовки. X-Frame-Options заменён директивой frame-ancestors, но его можно оставить со значением SAMEORIGIN для старых браузеров. X-XSS-Protection современными браузерами не поддерживается, и OWASP рекомендует не полагаться на него: не отправлять заголовок или отправлять значение 0.
Как внедрить заголовки за один день
Утро: HTTPS без исключений
- Сертификат на все домены и поддомены сайта с автоматическим продлением — например, через Let's Encrypt или в панели хостинга.
- Постоянный редирект (301) со всех адресов HTTP на HTTPS и на один основной домен.
- Поиск смешанного содержимого: картинки, скрипты, шрифты, подключённые по http://, — консоль браузера показывает предупреждения.
- Протоколы TLS 1.2 и TLS 1.3; TLS 1.0 и 1.1 отключаются.
Середина дня: HSTS и простые заголовки
HSTS включайте поэтапно. Сначала max-age на сутки и проверка, что всё работает; затем год — 31536000 секунд. Параметр includeSubDomains добавляйте, только когда проверены все поддомены, включая веб-интерфейс почты и старые стенды. Директиву preload и подачу домена в список предзагрузки браузеров на hstspreload.org оставьте на потом: сам сервис предупреждает, что удаление из списка может занять месяцы.
Затем добавьте X-Content-Type-Options, Referrer-Policy и Permissions-Policy и уберите номера версий ПО из заголовков Server и X-Powered-By — они подсказывают, какие известные уязвимости стоит искать.
Вечер: CSP в режиме отчётов
Content-Security-Policy — самый полезный и самый капризный заголовок. Не включайте его сразу в блокирующем режиме. Отправьте заголовок Content-Security-Policy-Report-Only: браузер будет сообщать о нарушениях политики, но ничего не заблокирует. Пример стартовой политики:
`` Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://analytics.example; img-src 'self' data: https:; style-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; report-uri /csp-report ``
Замените analytics.example на реальные домены систем аналитики, онлайн-чата и платёжных виджетов. Одну-две недели собирайте отчёты, добавляйте легитимные источники, выносите встроенные скрипты в файлы или помечайте их одноразовым значением nonce либо хешем. Когда отчёты затихнут, переименуйте заголовок в Content-Security-Policy и добавьте upgrade-insecure-requests. Учтите: директивы frame-ancestors и report-uri работают только в HTTP-заголовке, в теге meta они игнорируются.
Где настраивать: веб-сервер, CDN или CMS
Лучше всего — на веб-сервере или в CDN, одним блоком для всего сайта. Пример конфигурации для nginx:
``nginx add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; add_header Content-Security-Policy-Report-Only "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; report-uri /csp-report" always; ``
Две особенности nginx. Параметр always нужен, чтобы заголовки отправлялись и в ответах с ошибками. А если внутри блока location объявлен хотя бы один собственный add_header, заголовки уровня server в этом location не наследуются — их придётся повторить. В Apache аналог — директива Header always set, в CDN заголовки задаются правилами для ответов. Плагины CMS тоже умеют добавлять заголовки, но следите, чтобы они не дублировали серверные: если придут две разные политики CSP, браузер применит обе, и сработает самое строгое сочетание.
Как проверить результат
- Инструменты разработчика в браузере: вкладка «Сеть» показывает заголовки ответа, консоль — нарушения CSP.
- MDN HTTP Observatory — бесплатная оценка заголовков вашего сайта с рекомендациями.
- Командная строка: запрос только заголовков к своему сайту, например curl -I https://example.by.
- Не только главная: проверьте страницы ошибок, личный кабинет, API и статические файлы.
- После каждого релиза: новые виджеты и скрипты часто требуют правки CSP.
Типичные ошибки
- Включить includeSubDomains или preload, не проверив все поддомены.
- Сразу включить блокирующую CSP и потерять аналитику, онлайн-чат или оплату.
- Разрешить в CSP 'unsafe-inline' и 'unsafe-eval' для скриптов «чтобы работало» — такая политика почти не защищает от XSS.
- Настроить заголовки на страницах сайта, но забыть про личный кабинет и API — о защите программных интерфейсов подробно в статье про безопасность API.
- Дублировать заголовки в CMS и на сервере с разными значениями.
- Считать заголовки заменой исправлению уязвимостей в коде.
Чек-лист на один день
- Сертификат покрывает все домены, автопродление настроено.
- Редирект 301 с HTTP на HTTPS, смешанного содержимого нет.
- TLS 1.0 и 1.1 отключены.
- Strict-Transport-Security отправляется, max-age увеличен до года после проверки.
- includeSubDomains — только после проверки всех поддоменов.
- X-Content-Type-Options: nosniff.
- Referrer-Policy: strict-origin-when-cross-origin или строже.
- Permissions-Policy отключает неиспользуемые камеру, микрофон, геолокацию.
- frame-ancestors задан в CSP, X-Frame-Options оставлен для старых браузеров.
- CSP работает в режиме Report-Only, отчёты собираются, назначена дата перехода в блокирующий режим.
- Cookie сессии имеют атрибуты Secure, HttpOnly и SameSite.
- Номера версий ПО убраны из заголовков Server и X-Powered-By.
- Заголовки проверены на страницах ошибок, в личном кабинете и API.
Как это делает Viviar
Настройку заголовков мы проверяем в рамках технического аудита сайта и пентеста в направлении кибербезопасности. Для небольших компаний подходит «Цифровой Минимум» от 1 700 BYN: сканирование уязвимостей, проверка требований закона 99-З и список приоритетов, в котором заголовки обычно стоят среди быстрых исправлений. Если внедрять исправления некому, их берёт на себя команда разработки — например, по подписке от 4 400 BYN в месяц за 20 часов. Все пакеты — на странице цен.
Частые вопросы
Какие заголовки безопасности сайта обязательны?
Минимальный набор для любого сайта: Strict-Transport-Security, Content-Security-Policy хотя бы с директивами frame-ancestors, object-src и base-uri, X-Content-Type-Options со значением nosniff, Referrer-Policy и Permissions-Policy. Плюс атрибуты Secure, HttpOnly и SameSite у cookie сессии. Список заголовков с рекомендуемыми значениями ведёт OWASP Secure Headers Project.
Можно ли сломать сайт заголовками безопасности?
Да, если включать их без проверки. Чаще всего ломает строгая Content-Security-Policy — перестают работать аналитика, чаты и платёжные виджеты — и HSTS с includeSubDomains, когда часть поддоменов работает без HTTPS. Поэтому CSP сначала запускают в режиме Report-Only, а срок HSTS увеличивают постепенно, от суток до года.
Нужен ли X-Frame-Options, если есть CSP?
Директива frame-ancestors в Content-Security-Policy заменяет X-Frame-Options и гибче: позволяет перечислить конкретные разрешённые домены. Браузеры, поддерживающие frame-ancestors, при наличии обеих настроек ориентируются на неё. X-Frame-Options со значением SAMEORIGIN можно оставить для совместимости со старыми браузерами — конфликта при согласованных значениях не будет.
Что такое HSTS preload и стоит ли его включать?
Preload — включение домена в список, встроенный в браузеры: сайт открывается только по HTTPS даже при самом первом заходе. Требования — HSTS со сроком не меньше года, includeSubDomains и директива preload. Включайте, только когда все поддомены надёжно работают по HTTPS: удаление домена из списка может занять месяцы.
Сколько стоит настройка заголовков безопасности?
Если есть свой администратор, настройка по этой инструкции занимает один рабочий день плюс одну-две недели наблюдения за CSP. У Viviar проверка заголовков входит в «Цифровой Минимум» от 1 700 BYN вместе со сканированием уязвимостей, а внедрение исправлений можно поручить разработке по подписке от 4 400 BYN в месяц.
Вывод
Заголовки безопасности сайта — один из самых дешёвых способов ограничить последствия XSS, кликджекинга и перехвата трафика. За день включаются HTTPS, HSTS, X-Content-Type-Options, Referrer-Policy, Permissions-Policy и CSP в режиме отчётов, а через одну-две недели — блокирующая CSP. Двигайтесь поэтапно, проверяйте поддомены перед includeSubDomains и повторяйте проверку после релизов. Если нужна проверка конфигурации сайта или помощь с внедрением, напишите нам: ответим за 2 рабочих дня.
Источники: MDN Web Docs — Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, X-Frame-Options, HTTP Observatory (developer.mozilla.org); OWASP Secure Headers Project, OWASP HTTP Headers Cheat Sheet, OWASP Web Security Testing Guide (owasp.org); RFC 6797 «HTTP Strict Transport Security» (ietf.org); Content Security Policy Level 3 (w3.org); HSTS Preload List (hstspreload.org); документация nginx — модуль ngx_http_headers_module (nginx.org).